日志聚合架构:ELK vs Loki
服务跑在不同机器,日志散落各处,出事翻不到。日志聚合把所有日志集中一处,可搜可查可告警。本文讲清日志聚合的架构(采集→传输→存储→查询)、ELK(重)vs Loki(轻)的取舍、结构化日志(JSON)的重要性,以及怎么定日志策略(级别/采样/保留)。
本文要点
- 主题聚焦:DevOps
- 适合人群:独立开发者、全栈工程师、AI 应用开发者
- 核心价值:快速理解背景、实践路径、常见误区和工程建议
凌晨两点,支付服务报错。你 SSH 到第一台机器 tail -f,没有;第二台,没有;第三台……二十台机器翻完,发现关键日志在第十七台,而那台十秒前刚被自动扩容换掉了。这种剧本每个运维都演过:服务跑在不同机器、不同容器,日志散落在各处,出事时根本翻不到。
日志聚合要解决的就是这件事——把所有机器、所有容器的日志集中到一个地方,可搜、可查、可告警。这篇文章讲清它的四层架构、ELK 和 Loki 这两套主流方案的取舍、结构化日志为什么是一切的前提,以及怎么定一套能扛到生产的日志策略。
一、架构四层:采集 → 传输 → 存储 → 查询
不管选哪套方案,日志聚合的骨架都是四层。理解了这四层,看任何日志系统都不会迷路。
┌─────────────┐ ┌──────────┐ ┌──────────────┐ ┌─────────────┐
│ 采集层 │ → │ 传输层 │ → │ 存储索引层 │ → │ 查询可视化 │
│ filebeat │ │ (Kafka) │ │ Elasticsearch │ │ Kibana │
│ promtail │ │ 缓冲 │ │ / Loki │ │ / Grafana │
│ vector │ │ 可选 │ │ │ │ │
└─────────────┘ └──────────┘ └──────────────┘ └─────────────┘
每台机器跑 削峰填谷 建索引/压缩 人看/告警
采集层:每台机器(或每个节点)上跑一个轻量 agent,负责读日志文件、跟踪偏移量、贴标签、往上报。ELK 系用 Filebeat(老牌是 Logstash,但它太重,现在普遍只当处理节点);Loki 系用 Promtail;还有后起之秀 Vector(Rust 写的,性能好、配置统一)。采集器必须做到两件事:不重不漏(靠记录读取位置 offset,重启后接着读)和背压(下游堵了别把日志吞了,也别把自己撑爆)。
传输层:可选。日志量大、或下游会抖动时,中间塞一个 Kafka 做缓冲。好处是削峰填谷——下游存储挂了五分钟,日志先堆在 Kafka,不会丢。量小可以跳过这层,采集器直接推存储。很多中型团队跳过 Kafka 反而更省心,多一个组件多一份运维成本。
存储索引层:日志系统的核心,也是 ELK 和 Loki 分道扬镳的地方。这一层决定了"日志怎么存、查询快不快、费多少钱"。
查询可视化层:人最终打交道的地方。Kibana 配 ELK,Grafana 配 Loki,做的是写查询、画看板、配告警、按时间和字段过滤。
下面两节展开讲 ELK 和 Loki 在存储索引层的选择差异——这正是整套架构的命门。
二、ELK:重武器,全文搜索强
ELK = Elasticsearch + Logstash + Kibana。现在 Logstash 多被 Filebeat 替代,但名字保留下来了。它的核心是 Elasticsearch——一个基于 Lucene 的搜索引擎。
ES 的设计哲学是全字段索引。每条日志进来,它把所有字段都建倒排索引,正文还做分词。这意味着你拿到一条 {"msg":"order timeout","user_id":"8821"},不管将来按 user_id 查、按 msg 搜 "timeout"、还是组合 user_id=8821 AND msg:"timeout",都能快速命中。全文搜索是 ELK 的杀手锏——日志正文里任何一个词,都能搜出来。
代价是重。全字段索引意味着 CPU、内存、磁盘三重开销:
- 内存:ES 把索引热数据放内存(JVM heap + OS page cache),动辄几十 GB。一台 ES 节点没 32GB 内存跑不动。
- 磁盘:日志原文 + 索引,膨胀比常见 1:1.5 到 1:3。存 1TB 日志实际占 2–3TB。
- 运维复杂:ES 集群要管分片(shard)、副本(replica)、集群状态、版本升级,每个都是坑。分片数设少了扩容卡脖子,设多了元数据爆炸。
ELK 的优势在生态成熟、功能强:聚合分析、机器学习异常检测、SIEM 安全分析、APM……ES 公司靠这套生态活了很多年。如果你的核心诉求是"对日志正文做复杂的全文检索和聚合",ELK 是最稳的选择。 业务侧搜索(电商商品、文档库)也是 ES 的主场,日志只是它顺手做的事。
三、Loki:轻量级,只索引标签
Loki 是 Grafana 家的产品,设计哲学跟 ELK 正好相反——不索引日志正文,只索引标签。
打个比方,ES 是"给日志里每个词都建索引",Loki 是"给日志贴几个标签(服务名、级别、Pod 名),正文原样压缩存"。这非常像 Prometheus 的"日志版"——Prometheus 也只索引 metric 名 + 标签,不索引数值本身。Loki 把同一套思想搬到了日志上。
ELK: [service=api][level=error] + 正文全文索引 ← 重,但正文可搜
Loki: [service=api][level=error] + 正文只压缩存 ← 轻,只按标签+时间查
代价是不能(或很难)搜日志正文。Loki 的查询是"先按标签和时间圈出一批日志流(stream),再在结果里做正则过滤"。你查 error 这个词,Loki 得先把所有标签匹配的日志拉出来,再正则过滤——量一大就慢。所以 Loki 适合"按标签 + 时间范围"的查询,不适合"全库搜某个关键词"。
收益是省:
- 资源省:没全字段索引,CPU/内存/磁盘开销远低于 ES。同样规模日志,Loki 存储成本常是 ELK 的 1/5 到 1/10。
- 运维简单:单进程就能跑(生产要分布式但心智负担低),没有 ES 那套分片副本的折磨。
- 和 Prometheus/Grafana 一体:标签体系天然对齐,在 Grafana 里从指标面板直接下钻到日志,体感丝滑。看到 p95 飙高,点一下就拉出那台机器那段时间的日志——这是 ELK 要费劲拼凑才能做到的。
Loki 适合的场景:你绝大多数日志查询是"这个服务这段时间报了什么错""这个 Pod 重启前的日志",而不是"全库里谁提到了 timeout"。后者其实是少数派——大部分排查都是从指标/告警下钻,圈定服务和时间,再翻日志。
四、ELK vs Loki:怎么选
两套方案没有绝对优劣,看你的查询模式。给一张实战取舍表:
| 维度 | ELK | Loki |
|---|---|---|
| 索引策略 | 全字段 + 全文 | 只索引标签 |
| 资源开销 | 重(内存/磁盘大户) | 轻 |
| 全文搜索 | 强(杀手锏) | 弱(要拉流再正则) |
| 按标签/时间查 | 强 | 强(主场) |
| 运维复杂度 | 高(集群/分片) | 低 |
| 存储成本 | 贵 | 便宜 |
| 生态 | 成熟(搜索/APM/SIEM) | Grafana 一体 |
实战选型:多数中小团队,先上 Loki。理由是 90% 的日志查询都是"按服务 + 时间 + 级别"过滤,Loki 又快又便宜,和 Grafana 配合丝滑。等到真正遇到"必须全文搜索日志正文"的场景(合规审计要搜某关键词、业务日志要做文本分析),再引入 ES 处理那部分数据——而不是一开始就为 10% 的场景上 ELK,扛 100% 的成本。
反过来,如果你的业务本身就是搜索(电商、文档库、日志分析产品),或日志要做复杂聚合分析,ELK 的全文能力不可替代,直接上 ELK,别在 Loki 上硬凑正则。
一个常见的组合拳:Loki 做日常运维日志(量大、查询简单),ES 做少量需要深挖的业务日志(量小、查询复杂)。两套并存,各管一段。
五、结构化日志(JSON):一切的前提
不管 ELK 还是 Loki,日志是**结构化(JSON)**才有意义。这是采集之前就要在应用层做好的事。
# 反面教材:人看得爽,机器查不动
2026-07-18 10:23:11 ERROR User 8821 order failed: timeout calling payment
# 正确做法:JSON,字段可索引可过滤
{"ts":"2026-07-18T10:23:11.123Z","level":"error","msg":"order_failed",
"service":"order-api","user_id":"8821","error":"timeout","downstream":"payment",
"trace_id":"a3f9c2","duration_ms":8203}
结构化日志有三个价值:
- 机器可查:ELK/Loki 都能直接按
user_id=8821、downstream=payment过滤,不用写正则从句子里抠字段。非结构化日志要么靠 Grok/LogQL 正则解析(慢、脆、容易错),要么干脆不能按字段查。 - 对接 trace:
trace_id作为字段存进去,日志就能和链路关联——从 trace 跳日志、从日志跳 trace,排查路径打通。 - 采集成本低:JSON 直接序列化传输,采集器不用做解析。Promtail/Filebeat 都支持按 JSON 字段自动提取标签。
所有服务的日志都应该 JSON 输出,这是团队规范级别的事,不是个人偏好。Node 用 pino、Python 用 structlog 或 json formatter、Go 用 zap/slog——每个语言都有成熟的结构化日志库,没有理由再写人看的句子。
六、日志策略:级别、采样、保留
日志聚合系统搭好,不代表什么日志都收。一套能扛到生产的日志策略要回答三个问题:记什么级别、采多少、留多久。
级别:
- debug:开发排查用,生产默认关或极低采样。
- info:关键业务事件(下单、支付、登录),正常路径节点。
- warn:异常但可恢复(重试成功、降级、限流触发)。
- error:真出错了,需要人介入。error 不能当垃圾桶——用户校验失败、第三方 429 这类不是系统错误,塞进去会让真错误被淹没。
采样:高 QPS 路径不能全量打。一个 10 万 QPS 的接口每条 info 都记,一天 86 亿条,存储费比服务器还贵。常见做法是健康请求采样 1%,异常请求 100%。Loki 在采集层就能做采样,ES 侧则在应用层控制。采样不是丢数据,是用统计学换成本——1% 的样本足够还原整体长什么样,而错误一条都不能漏。
保留:日志不能无限存,按价值分层:
- 热数据(7 天):最近日志,SSD,查询快,日常排查用。
- 温数据(30 天):转低成本磁盘或对象存储,偶尔回溯用。
- 冷归档(90 天+):压缩丢 S3/OSS,基本不查,合规留存。
ES 用 ILM(Index Lifecycle Management)自动分层;Loki 用 boltdb-shipper + S3 后端,天然支持冷热分层。保留期要和合规要求对齐——金融、医疗等行业有最低留存年限,别为了省钱提前删。
七、日志、指标、trace:互补不替代
最后澄清一个常见误解:有了日志聚合,是不是就不用 Prometheus 了?不是。日志、指标、trace 是可观测三支柱,各管一件事,互补不替代。
- 日志(详情):离散事件记录,告诉你"这次具体发生了什么"。贵、量大、适合深挖。
- 指标(聚合数字):时间序列数值,告诉你"整体趋势什么样"。便宜、适合告警和看板。错误率、QPS、p95 延迟这些,不该靠数日志算,该用 Prometheus 直接埋。
- trace(请求链路):一次请求跨服务的树状记录,告诉你"这笔慢在哪一跳"。适合定位分布式系统的瓶颈。
三者配合的典型路径:指标告警("支付错误率涨了")→ trace 定位("慢在调银行网关那一跳")→ 日志深挖("那一次网关返回了 timeout")。用日志算指标是最贵的做法——每秒扫几亿条日志算错误率,远不如 Prometheus 直接存好曲线。日志的价值在详情,不在聚合。三者靠 trace_id 串成一张网,这套联动才是"可观测",而不是三个孤立的系统。
小结
- 日志聚合解决"集中可搜":服务跑在不同机器,SSH 翻日志是上一个时代的玩法。采集 → 传输 → 存储 → 查询四层架构,是所有日志系统的通用骨架。
- ELK 强在全文搜索,贵在重:ES 全字段索引让日志正文可搜,代价是内存/磁盘/运维三高。适合业务就是搜索、或要复杂文本分析的场景。
- Loki 强在轻省,弱在正文搜索:只索引标签、和 Grafana 一体,资源开销是 ELK 的零头。多数运维日志查询(按服务+时间+级别)它都够用,中小团队先上 Loki。
- 结构化日志(JSON)是一切的前提:机器可查、对接 trace、采集低开销。所有服务日志都该 JSON 输出,这是规范不是偏好。
- 策略决定成本:级别别当垃圾桶、高 QPS 路径采样、按热/温/冷分层保留。日志费不费钱,策略比选型更关键。
- 日志、指标、trace 互补不替代:日志查详情、指标看趋势、trace 定链路,靠 trace_id 串成一张网。用日志算指标是最贵的反模式。
一句话收尾:日志聚合系统值不值钱,不在于你选了 ELK 还是 Loki,而在于出事那一刻,你能不能十秒内把"那台机器、那段时间、那个 trace_id"的日志拉出来。 工具是手段,可查才是目的。
Related
相关推荐
文章
Docker 部署 Next.js 社区项目的注意事项
围绕 DevOps、Next.js 的技术趋势、工程实践和独立开发视角。
文章
OpenTelemetry 如何帮助你观察 AI 应用?
围绕 DevOps、AI 的技术趋势、工程实践和独立开发视角。
文章
长运行工具调用:Operation、Poll 与 Cancel 的终态协议
初始请求超时后,工具可能仍在服务端运行;发出取消也不等于副作用已停止。本文为单次长运行工具调用建立 operation 身份、轮询水位、取消竞态和唯一终态接受点。
文章
Agent 记忆删除传播:从用户遗忘请求到可验证清除
删除主表一行不会清掉向量、摘要、缓存和恢复后的备份。本文用删除状态机、代际墓碑、派生血缘与端到端 canary 验证真正遗忘。