#DevOps

日志聚合架构:ELK vs Loki

服务跑在不同机器,日志散落各处,出事翻不到。日志聚合把所有日志集中一处,可搜可查可告警。本文讲清日志聚合的架构(采集→传输→存储→查询)、ELK(重)vs Loki(轻)的取舍、结构化日志(JSON)的重要性,以及怎么定日志策略(级别/采样/保留)。

本文要点

  • 主题聚焦:DevOps
  • 适合人群:独立开发者、全栈工程师、AI 应用开发者
  • 核心价值:快速理解背景、实践路径、常见误区和工程建议
作者 @admin·发布于 2026年3月19日·更新于 2026年7月23日

凌晨两点,支付服务报错。你 SSH 到第一台机器 tail -f,没有;第二台,没有;第三台……二十台机器翻完,发现关键日志在第十七台,而那台十秒前刚被自动扩容换掉了。这种剧本每个运维都演过:服务跑在不同机器、不同容器,日志散落在各处,出事时根本翻不到。

日志聚合要解决的就是这件事——把所有机器、所有容器的日志集中到一个地方,可搜、可查、可告警。这篇文章讲清它的四层架构、ELK 和 Loki 这两套主流方案的取舍、结构化日志为什么是一切的前提,以及怎么定一套能扛到生产的日志策略。

一、架构四层:采集 → 传输 → 存储 → 查询

不管选哪套方案,日志聚合的骨架都是四层。理解了这四层,看任何日志系统都不会迷路。

text
┌─────────────┐    ┌──────────┐    ┌──────────────┐    ┌─────────────┐
│  采集层      │ →  │  传输层    │ →  │  存储索引层   │ →  │  查询可视化  │
│ 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 把同一套思想搬到了日志上。

text
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:怎么选

两套方案没有绝对优劣,看你的查询模式。给一张实战取舍表:

维度ELKLoki
索引策略全字段 + 全文只索引标签
资源开销重(内存/磁盘大户)轻
全文搜索强(杀手锏)弱(要拉流再正则)
按标签/时间查强强(主场)
运维复杂度高(集群/分片)低
存储成本贵便宜
生态成熟(搜索/APM/SIEM)Grafana 一体

实战选型:多数中小团队,先上 Loki。理由是 90% 的日志查询都是"按服务 + 时间 + 级别"过滤,Loki 又快又便宜,和 Grafana 配合丝滑。等到真正遇到"必须全文搜索日志正文"的场景(合规审计要搜某关键词、业务日志要做文本分析),再引入 ES 处理那部分数据——而不是一开始就为 10% 的场景上 ELK,扛 100% 的成本。

反过来,如果你的业务本身就是搜索(电商、文档库、日志分析产品),或日志要做复杂聚合分析,ELK 的全文能力不可替代,直接上 ELK,别在 Loki 上硬凑正则。

一个常见的组合拳:Loki 做日常运维日志(量大、查询简单),ES 做少量需要深挖的业务日志(量小、查询复杂)。两套并存,各管一段。

五、结构化日志(JSON):一切的前提

不管 ELK 还是 Loki,日志是**结构化(JSON)**才有意义。这是采集之前就要在应用层做好的事。

text
# 反面教材:人看得爽,机器查不动
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}

结构化日志有三个价值:

  1. 机器可查:ELK/Loki 都能直接按 user_id=8821、downstream=payment 过滤,不用写正则从句子里抠字段。非结构化日志要么靠 Grok/LogQL 正则解析(慢、脆、容易错),要么干脆不能按字段查。
  2. 对接 trace:trace_id 作为字段存进去,日志就能和链路关联——从 trace 跳日志、从日志跳 trace,排查路径打通。
  3. 采集成本低: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

相关推荐