第4章:日志存储选型——Elasticsearch、Loki、ClickHouse对比

好了,选存储这件事,其实比选采集器更让人头疼。

我一个老同事说过:「日志存好了,后面告警和分析就顺了;存错了,后面改起来能让你哭。」这话不夸张。我见过不少团队,一开始图省事全塞 Elasticsearch,结果磁盘爆了;也有人一股脑用 Loki,结果想查详细链路时发现字段不全。说白了,没有银弹。

4.1 三巨头的核心差异

先看一张总览表。我习惯用这个表给新同事做入门,简单直接。

特性 Elasticsearch Loki ClickHouse
数据模型 倒排索引 + JSON 文档 只追加日志流 + 标签 列式存储 + SQL 表
全文检索 天生强项,分词、模糊匹配都行 弱,仅支持日志行内容扫描 需要额外插件或 full-text 索引
写入性能 中等,依赖分片数和节点数 极高,几乎无解析开销 非常高,批量写入是设计初衷
查询延迟 秒级,复杂聚合稍慢 毫秒级,针对时间范围 + 标签 毫秒到秒级,聚合极快
存储成本 高,副本 + 索引占用大 低,几乎无索引,压缩比高 中等,列式压缩,但需要排序键
运维复杂度 较高,需要调 JVM、分片 简单,组件少,易水平扩展 中等,集群配置需要经验
典型场景 全量日志检索、APM、安全审计 Kubernetes 容器日志、实时监控 结构化日志、Metrics、分析型查询

你看,每个都有自己的地盘。我们一个一个细说。

4.2 Elasticsearch——全能选手,但贵

ES 几乎是日志存储的代名词了。我早期做的几个项目,都是直接上 ES。优点是太明显了:

  • 建好索引模板,什么格式的日志都能往里塞
  • Kibana 的 Discover 页面,看日志像看聊天记录
  • DSL 查询强大,支持 nested、range、wildcard 各种花式查
我个人习惯:在 IM 通道日志里,ES 用来存所有原始日志,保持 7~30 天的保留期。这样出问题时可以回看完整上下文。

但一个问题:贵。我举个例子,一个每天 100GB 日志的 IM 通道,如果保留 30 天,ES 集群至少需要 5 个节点。磁盘、内存、CPU 都吃紧。我曾经遇到过,某个客户的日志量突然翻倍,ES 集群直接 OOM,导致整个告警系统瘫痪。嗯,这个坑我踩过。

避坑指南:不要把所有索引副本数都设为 2。对于 IM 通道日志,副本 1 就够了。还有,别用默认动态映射(dynamic mapping),提前定义好字段类型。否则 ES 会被字符串字段撑爆。

4.3 Loki——云原生日志,又轻又快

这几年 Loki 慢慢就火起来了,尤其在 Kubernetes 环境。说白了,它不建全文索引,只存日志内容和标签元数据。这意味着:

  • 写入开销极低,几乎可以忽略
  • 存储占用只有 ES 的 1/3 甚至更低
  • 原生支持 Prometheus 标签体系,集成起来很顺

但 Loki 不是万能的。你想,它不支持全文检索那种模糊匹配,只能扫日志行内容。如果 IM 通道日志里某个关键字段是随机 ID,你没法用「like」查,只能靠标签。我建议这样用:

  • 把通道 ID、消息类型、错误码作为标签
  • 日志正文保持原始文本
  • 聚合分析靠 LogQL 的 unwrap 和 pattern parsing
贴士:Loki 的 boltdb-shipper 模式已经成熟,不用额外搭 Cassandra 或 S3 后端,单机就能跑。适合中小团队。

我曾经帮一家公司迁移日志平台,从 ES 转到 Loki,季度费用直接从 5 万美元降到了 1.2 万。降本很明显,但代价是丧失了灵活检索能力。所以选不选 Loki,得看你的查询模式。

4.4 ClickHouse——极速查询,分析利器

ClickHouse 本来是给分析场景用的。但后来很多人发现,拿它存日志也挺香。特别是你需要做大量聚合、统计、漏斗分析的时候。

它的列式存储让扫描速度惊人。举个例子:在 1TB 的日志表里查某个错误码的出现次数,ES 可能要 5 秒,ClickHouse 几百毫秒就出结果了。

-- 一个典型的日志分析查询
SELECT 
    error_code,
    count() AS cnt,
    countIf(channel_id = 'wechat') AS wechat_cnt
FROM im_channel_logs
WHERE event_time > now() - INTERVAL 1 HOUR
GROUP BY error_code
ORDER BY cnt DESC
LIMIT 10;
我个人的经验:ClickHouse 最适合做结构化日志的时序分析。比如 IM 通道的响应时延 P99、失败率、通道健康分。这些指标如果从 ES 查,慢到怀疑人生。

但 ClickHouse 不适合存原始日志全文检索。它没有倒排索引,你想搜某一个用户消息里的关键词,很难。还有,我建议不要让它频繁执行小查询(比如每 10 秒刷一次)。这东西是批量分析型选手。

嗯,这里要注意:ClickHouse 的 MergeTree 排序键设计很关键。用不好,查询性能可能差一百倍。

避坑指南:我曾经在客户的集群上,看到有人把排序键设成了 message。大错特错。message 字段重复度高、长度大,压缩率极差,写入像乌龟爬。应该用 event_time + channel_id 这类高基数的字段。

4.5 选型建议——三个维度搞定

怎么选?我总结了一个三问法,你可以拿来直接用:

  1. 你需要全文检索吗? 需要 → ES;不需要 → Loki 或 ClickHouse
  2. 你主要是看实时告警,还是做历史分析? 实时告警多 → Loki;历史报表多 → ClickHouse
  3. 预算充足吗? 充足 → ES 加 ClickHouse 组合;紧张 → Loki + ClickHouse 混搭

我个人推荐的一个成熟方案是这样的:

  • 所有原始日志走 Loki,保留 7~15 天,用于快速查看和告警
  • 抽取关键指标和结构化日志进 ClickHouse,保留 30~90 天,用于趋势分析和报表
  • 如果需要全文检索,再加一个小型 ES 集群,只存重试日志、错误堆栈等关键类

下图是这个架构的简化版本,也覆盖了前面几章讲的内容。

日志存储选型架构图 日志采集层 Filebeat / Fluent Bit / Promtail Elasticsearch Loki ClickHouse 场景:全量原始日志 保留 7~30 天 支持全文检索、Kibana 展示 适合故障回溯和安全审计 场景:实时告警 & 监控 保留 7~15 天 低存储成本,原生 K8s 集成 适合链路追踪和快速查看 场景:趋势 & 报表分析 保留 30~90 天 极速聚合查询、指标计算 适合 P99 延迟、错误率分析 告警 & 展示层 Grafana / AlertManager / 自研通知引擎

你看,这个架构里三层分工明确。采集层统一收日志,存储层根据场景选,告警展示层统一配置。

贴士:我建议你画一张类似上面的图,贴在团队 wiki 上。每个新人来,先看这张图,再动手,能少踩好多坑。

最后再说一句。存储选型其实没有的对错。我见过只用 ES 跑得很好的团队,也见过只用 Loki 活下来的公司。关键看你掌握了什么、团队有什么经验、业务要什么。