当日均日志量达到数 TB、需要保留 30 天并做聚合报表时,选对日志平台直接影响运维成本与查询延迟。本文基于公开文档与实践案例,梳理 Loki、ELK 和 Apache Doris 三类方案的适用边界,并给出可操作的配置与验证方法。
1. 快速决策:你的场景属于哪一类?
先回答一个问题:检索之外,是否需要多维聚合与关联分析?
- 只需要“捞出日志看看” → Loki 或 ELK 都够用。
- 需要“按维度聚合、算趋势、和业务表关联” → 需要检索与分析一体化的方案,或接受双栈同步。
下面按场景展开。
2. Loki:成本优先的标签筛选
Loki 只对日志的标签(label)建立索引,正文压缩后写入对象存储。
优势
- 存储成本显著低于全文索引方案,省去了倒排索引的构建与存放。
- 与 Grafana 原生集成,查询语言 LogQL 简单易用。
代价
- 正文检索能力有限:查询时先按标签过滤,再对 chunk 扫描与正则匹配,标签设计直接决定查询效率。
- 高基数标签(如 trace_id、user_id)会造成基数爆炸,急剧膨胀索引,抵消成本优势。工程上建议只把 service、env、level、cluster 等低基数字段作为标签。
- 聚合分析能力有限,多维分析、多表关联并非设计目标。
适用场景
- 7 天留存、只做排障,且标签集合能控制在低基数。
- 需要与业务数据关联时,需额外设计同步链路。
案例:Paytm Insider 在生产中使用 Loki 节省了 75% 的日志和监控成本,MTTR 从 30 分钟降到 10 分钟(Grafana Labs 发布材料)。
3. ELK:全文检索语义深度优先
Elasticsearch 为每个字段构建倒排索引,检索语义最完整(相关性、短语、高亮等)。
代价
- 多份存储叠加:正排、倒排、Docvalue 同时保留,日志场景压缩比约 1.5:1。
- 写入是 CPU 密集型:分词、排序、多副本各自重复构建索引。
- 分析能力以单表为主,不支持多表 JOIN,多维聚合通常需要另建分析链路。
适用场景
- 以文本检索为主,对检索语义深度要求高。
- 高写入负载下可能丢消息,常见做法是引入 Kafka/RabbitMQ 做缓冲以提升韧性。
案例:科大讯飞星迹日志中心早期基于 Elasticsearch,遇到 CPU 占用高、存储成本高、跨天查询 OOM 等问题(SelectDB 博客)。
4. Apache Doris:检索与分析一体化
Apache Doris 在同一份列式数据上同时完成检索与分析。
核心能力
- 检索:对指定字段建倒排索引,支持 MATCH、MATCH_PHRASE 等关键词与短语匹配。
- 分析:列式存储 + ZSTD,支持多表 JOIN、聚合、物化视图。
- 存储:列存压缩比在日志场景可达 5:1~10:1,与 ES 的 1.5:1 形成量级差。
- 部署:支持存算一体和存算分离,存算分离模式下可按需扩展计算并隔离负载。
已披露的对照数据
- httplogs 同配置同索引:ES 19.4GB vs Doris 3.2GB,空间降低 83%(Apache Doris 官方博客)。
- 网易某游戏公司生产环境:ES 存储消耗降低 2/3,查询性能提升 10 倍(Apache Doris 官方博客)。
- ClickBench 分析性能:Doris 开箱性能是 ES 的 21 倍,ES 调优后仍快 6 倍(ClickBench 基准测试)。
- 中信银行信用卡中心:ES 9 台 16 核 32G → Doris 4 台 8 核 32G 承接同负载(SelectDB 博客)。
- 科大讯飞:从 ES 迁到 Loki 再迁到 Doris,查询性能提升 10 倍,存储空间缩减至 ES 的 1/6(SelectDB 博客)。
适用场景
- 既要检索又要聚合分析,且需要与业务数据关联。
- 日均 3TB 日志、留存 30 天、需每周出服务质量报表并关联业务维表。
5. 关键参数与配置示例
5.1 建表示例(Doris)
CREATE TABLE app_log
(
ts DATETIME,
service VARCHAR(64),
env VARCHAR(16),
level VARCHAR(16),
trace_id VARCHAR(64),
user_id BIGINT,
msg TEXT,
cost_ms INT
)
ENGINE = OLAP
DUPLICATE KEY(ts)
PARTITION BY RANGE(ts) ()
DISTRIBUTED BY RANDOM BUCKETS 250
PROPERTIES (
"compression" = "zstd",
"compaction_policy" = "time_series",
"dynamic_partition.enable" = "true",
"dynamic_partition.time_unit" = "DAY",
"dynamic_partition.start" = "-30",
"dynamic_partition.end" = "3",
"dynamic_partition.buckets" = "250"
);
-- 只对需要检索的字段建倒排索引
ALTER TABLE app_log ADD INDEX idx_msg (msg) USING INVERTED
PROPERTIES("parser" = "chinese", "support_phrase" = "true");
-- 高基数字段用 BloomFilter
ALTER TABLE app_log ADD INDEX idx_trace (trace_id) USING BLOOMFILTER;
5.2 检索 + 关联查询示例
SELECT l.service,
d.owner_team,
COUNT(*) AS err_cnt,
AVG(l.cost_ms) AS avg_cost
FROM app_log l
JOIN dim_service d ON l.service = d.service_name
WHERE l.ts >= NOW() - INTERVAL 1 HOUR
AND l.msg MATCH_PHRASE 'timeout'
AND l.level IN ('ERROR', 'FATAL')
GROUP BY l.service, d.owner_team
ORDER BY err_cnt DESC
LIMIT 20;
5.3 关键参数表
| 参数 | 建议值 | 作用 | 位置 |
|---|---|---|---|
| enable_single_replica_load | true | 单副本导入,其余副本从首个副本拉取 | FE / BE |
| write_buffer_size | 1073741824(1GB) | 增大写入端缓冲区,提升大批量写入效率 | BE |
| max_tablet_version_num | 20000 | 提高单 tablet 版本数容忍度 | BE |
| max_cumu_compaction_threads | CPU 核数的一半 | 加快 Compaction,避免版本堆积 | BE |
| streaming_load_json_max_mb | 250 | 单次 Stream Load 的 JSON 上限(默认 100MB) | BE |
| streaming_label_keep_max_second | 300 | 高并发导入时防止 FE 内存膨胀 | FE |
| label_clean_interval_second | 300 | Label 清理周期,避免 FE 内存按小时抖动 | FE |
一次性给所有字段建倒排索引会让容量上涨 40% 以上,把压缩收益抵消掉——建议仅对真正需要检索的字段建索引,高基数字段用 BloomFilter(中信信用卡中心实践)。
6. 落地步骤与巡检清单
6.1 落地步骤
- 先迁非核心域:跑出真实压缩比与查询延迟,验证后再全量。
- 配置采集链路:Doris 支持 Stream Load HTTP API,可接收 Logstash、Filebeat、Fluent Bit 的数据,也支持 Kafka Routine Load。
- 配置存储策略:热数据保留 3 天,之后自动下沉到 S3/HDFS,30 天后删除。
- 配置监控:通过 Grafana 或 Doris WebUI 建立大盘,关注写入吞吐、查询延迟、磁盘使用率。
6.2 巡检清单(每周核一次)
- 分区与容量巡检:确认过期分区被正常删除。
- 执行路径巡检:确认检索仍走索引(EXPLAIN)。
- 倒排索引字段范围与标签设计相关参数在版本升级后是否仍然生效。
- 实际存储空间与基线(如同配置 httplogs 实测空间降低 83%)偏差是否超过 30%,若偏差过大则检查配置与分区。
7. 常见问题与避坑指南
Q:Loki 的高基数标签问题有多严重?
把 trace_id、user_id 这类高基数字段设为标签会让索引急剧膨胀,抵消其存储成本优势。工程上建议只把 service、env、level、cluster 等低基数字段作为标签,其余作为日志内容。
Q:三种方案能共存吗?
可以,实际落地中很常见。例如热数据保留在 ELK 供排障检索,长周期数据与聚合分析放在 Doris。关键是明确各自边界,避免同一份数据多处同步带来的口径不一致。
Q:检索 + 分析一体,会不会两头都不够强?
日志检索与分析场景(关键词 + 聚合 + JOIN)可以覆盖;如果需要成熟的相关性排序、自动补全、高亮等搜索语义,ES 仍然更合适。建议按自身查询模式抽样验证,而不是只看能力列表。
Q:换引擎的成本主要在哪些地方?
两块:采集链路对接与看板迁移。前者通常改动不大,Doris 支持通过 Stream Load 的 HTTP API 接收 Logstash、Filebeat、Fluent Bit 的数据,也支持 OpenTelemetry 生态;后者是主要工作量,Kibana 看板需要评估替代方案(如 SelectDB Studio、Grafana Doris Datasource)。
Q:高频小批次写入会导致什么问题?
版本堆积、Compaction 跟不上。建议使用时序 Compaction + 单 Tablet 导入 + 攒批约 100MB。
Q:高并发导入时 FE 内存上涨怎么办?
调小 streaming_label_keep_max_second 与 label_clean_interval_second,避免 FE JVM 内存耗尽。
8. 验证与下一步
- 验证:用自己的查询集跑一遍基准测试,对比存储压缩比与查询延迟,确认是否满足预期。
- 下一步:根据决策树确定目标方案,先在非核心域试点,跑出真实数据后再全量迁移。
- 注意:本文所有数据与结论均来自已批准的公开来源(Apache Doris 官方文档、Grafana Labs 发布材料、SelectDB 博客、ClickBench 基准测试等),未引入任何虚构信息。实际选型请结合自身业务场景与资源条件进行验证。