日志聚合与查询:Loki 与 ELK 选型实践
当服务从一台服务器扩展到几台、几十台,grep 日志的方式就失效了:故障信息分散在不同主机,你必须先找到"哪台机器的哪个文件"。集中式日志聚合把分散日志收进一个统一平台,再用查询语言快速定位问题。主流的开源方案是 ELK(Elasticsearch + Logstash + Kibana)与 Grafana Loki 两类,它们的架构哲学差异很大。
ELK:全文本索引的传统方案
ELK 是日志分析的老牌标准:Filebeat 采集、Logstash 过滤转换、Elasticsearch 对每条日志的全部内容建索引,Kibana 负责查询与可视化。全文本索引带来极强的搜索能力——任意字段、任意关键词都能秒级检索——这是它长期称霸的原因。代价也很直接:索引越全,存储与算力成本越高,量一大账单就很可观。
Loki:只索引标签的云原生方案
Grafana Loki 的设计哲学正相反。按官方文档,Loki"不对日志内容建索引,只索引一组标签(labels)"。日志被收集端(如 Grafana Alloy 或 Promtail)加上标签后按**流(stream)**组织,正文压缩后存进低成本对象存储(S3、GCS 或 Azure Blob Storage),索引体积因此远小于其它日志聚合工具。
这个设计带来三个直接好处:
- 成本低:小索引 + 高度压缩的 chunk + 廉价对象存储,让 Loki 比全索引方案便宜得多,官方声称从树莓派到每天 PB 级都能扩展。
- 查询快:查询时先用标签定位流,再只取并解压匹配的 chunk,所以"选择低基数、高质量标签"是查询性能的关键。
- LogQL 亲和 Prometheus:熟悉 PromQL 的人几乎零成本上手 LogQL,而且能用日志直接生成指标。
一张表看懂两者的取舍
| 维度 | ELK | Loki |
|---|---|---|
| 索引策略 | 全文索引每条日志 | 只索引标签 |
| 存储 | 依赖 Elasticsearch 集群 | 对象存储 + 小索引 |
| 查询语言 | KQL / Lucene | LogQL |
| 运维成本 | 高(集群调优) | 低(单二进制可跑) |
| 检索能力 | 任意字段全文检索 | 标签过滤 + 行内过滤 |
| 适合规模 | 中大型、重分析 | 中小型、云原生 |
选型没有绝对对错,核心是看你的查询模式:如果 90% 的排查都是"先按服务、环境过滤,再看 ERROR 日志",Loki 完全够用;如果经常要对任意字段做即席聚合分析,ELK 更顺手。
标签与 LogQL 的核心实践
Loki 的查询性能几乎完全取决于标签设计。好的标签应满足"低基数":例如 job、environment、service、instance 这类取值有限的维度;不要把 request_id、用户 ID 这类高基数信息放进标签,它们会拆出大量流、拖慢查询。典型的 LogQL 查询如下:
{job="api", environment="prod"} |= "ERROR"
| json
| line_format "{{.message}}"
Loki 还内置 ruler 组件,可以持续对日志执行查询、命中后告警,并集成 Prometheus Alertmanager 或 Grafana 告警——这让你能基于日志(如"过去 5 分钟 5xx 日志超过 50 条")直接产生告警,而不用先转成指标。
从日志生成指标也很常见,比如"统计每个服务的错误率":
sum by (service) (
rate({job="api"} |= "ERROR" [5m])
)
配合 count_over_time 可以统计一段时间内某个模式出现的次数。这类查询可以直接喂给 Grafana 面板,或交给 ruler 做阈值告警,让"日志"和"指标"两条链路互相印证。
如何选型
- 已有 Grafana 全家桶、Kubernetes 环境、预算敏感:选 Loki,与 Mimir、Tempo 天然打通指标-日志-链路。
- 需要任意字段全文检索、复杂分析、合规审计:选 ELK,Elasticsearch 的搜索能力仍是强项。
- 混合:用 Loki 做主日志、把关键系统日志同步一份到 Elasticsearch 做深度检索,也是一种务实做法。
一个真实场景:排查 503 故障
某次线上出现间歇性 503,没有集中日志之前,排查要这样进行:登录每台机器、分别 tail 各自的 nginx 和业务日志、肉眼比对时间戳,往往一两个小时才能定位到"某台机器内存被打满"。接入 Loki 之后,同一问题的排查路径变成:打开 Grafana,输入 {job="nginx", environment="prod"} |= "503" | json,再按 upstream 字段聚合,几分钟就发现错误集中在两台旧规格机器上。这不是 Loki 独有的能力,ELK 同样能做到——差别在于:Loki 以更低的存储成本让你"敢"把所有环境、所有服务的日志都收进来。日志收得越全,这类问题定位得越快。
采集与保留策略
Promtail(或新一代的 Grafana Alloy)负责采集,典型配置是监听容器或文件目录、打上 job/service 等标签后推送。retention 直接配置在 Loki 侧,比如"热数据保留 7 天、冷数据 30 天",配好后 Loki 会自动清理过期 chunk,不需要像 ELK 那样手动管理索引生命周期。对预算有限的中小团队,这是非常实际的省心点。
常见问题
- Loki 能全文搜索吗? 能,但方式不同:先用标签定位到流,再在行内做
|=、|~过滤。它不适合"不知道标签、纯靠正文关键词盲搜"的场景。 - 日志太多怎么办? 检查标签基数,把
request_id、用户 ID 从标签里拆出去;再不行就加采样或只收 WARN 以上级别。 - Loki 和 Prometheus 什么关系? 互补:Prometheus 管指标,Loki 管日志,两者通过 LogQL 的 metric 查询可以互相印证。
16IDC 观察
对独立站与中小团队,日志聚合的优先级往往被低估:很多"排查了两小时"的故障,其实有了集中查询后两分钟就能定位。可以先从 ELK 日志分析平台搭建或 Loki 单机版起步;Linux 主机的基础日志能力见 服务器日志监控指南。日志与指标、链路的关联可参考 APM 与分布式追踪,用日志生成告警则结合 Prometheus 告警规则设计。更多内容请查看 监控报警分类。
原文来源:https://grafana.com/docs/loki/latest/get-started/overview/
参考:LogQL 参考文档 https://grafana.com/docs/loki/latest/query/
参考:Grafana Alloy 文档 https://grafana.com/docs/alloy/latest/