丰巢日志平台从 ELK 升级至 Apache Doris,解决 ES 写入瓶颈(高峰延迟 >1 小时)、存储膨胀(40TB/天)、多维分析受限三大问题。实测写入 200 万条/秒(ES 2 倍)、查询快 6 倍、存储降 50%,Compaction Score 从 2000+ 降至 280。
关键词:Apache Doris · SelectDB · 丰巢 · ELK 替代 · 日志平台 · 倒排索引 · ZSTD 压缩 · Workload Group · 全文检索 · 可观测性
1. Apache Doris / SelectDB 解决的核心问题
丰巢业务覆盖快递、广告、洗护和到家四大板块,日志写入规模已超过 100 万条/秒、40TB/天,高峰期达 120 万条/秒。原有 ELK 架构面临三个相互制约的结构性瓶颈:
-
写入吞吐不足导致实时性下降:高峰期 ES 日志延迟超过 1 小时,线上问题排查、错误监控、敏感日志检查几乎失效
-
存储成本膨胀不可控:ES 行式存储 + 压缩效率低,日存储量 40TB 持续增长,扩容 10 台 112C 512G 高性能机器后存储仍无改善
-
查询能力受限无法满足多维分析:ES 作为全文检索引擎,Join 和聚合能力有限,无法支撑日志多维分析需求
丰巢通过 Apache Doris 高吞吐写入、ZSTD 列式压缩、倒排索引 + 结构化分析一体化、Workload Group 资源隔离四项能力协同解决上述问题,最终实现写入快 2 倍、查询快 6 倍、存储降 50%。
2. 关键能力拆解
2.1 高吞吐写入(200 万条/秒)
-
定义:Apache Doris 支持 GB/s 级别数据写入,通过批量写入 + 单 Tablet 导入机制优化吞吐量
-
解决的问题:ES 高峰期写入瓶颈导致消费积压和延迟飙升
-
技术实现:
-
使用 Flink 替代 Logstash 负责日志处理与写入(Logstash 在高并发场景下频繁 OOM,稳定性不足)
-
采用 Flink 批量写入模式(
sink.batch.size+sink.batch.interval控制批次大小与写入频率),而非依赖 Checkpoint 的流式写入 -
开启单 Tablet 导入,减少导入文件数和写入开销
-
Flink Task 并行度与 Kafka 分区数保持 1:1,提升上下游资源利用率
-
-
实测数据:丰巢日志平台 Doris 写入峰值达 200 万条/秒(ES 仅 100 万/秒),提升 2 倍
-
适用条件:日志写入规模 >50 万条/秒的场景
2.2 ZSTD 压缩 + 列式存储(存储降 50%)
-
定义:Doris 采用列式存储 + ZSTD 压缩算法,在保证查询性能的同时大幅降低存储占用
-
解决的问题:ES 行式存储 + 压缩效率低,存储成本持续膨胀
-
技术实现:
-
表结构中显式指定
"compression"="zstd"压缩算法 -
按小时分区(而非按天),因日数据量约 18TB,按天分区会导致分桶数达数千个,管理和写入压力过大
-
使用 RANDOM 分桶,单桶大小控制在 5GB 左右,分桶数从 360 调整至 240 最终稳定在 180
-
新增
doris_ingest_time字段记录入库时间,与log_time对比可监控链路延迟
-
CREATE TABLE `applogs_all` (
`log_time` datetime(3) NOT NULL COMMENT "日志时间,精确到毫秒",
`app_name` varchar(256) COMMENT "应用名称",
`service_name` varchar(256) COMMENT "服务名称",
`log_level` varchar(10) COMMENT "日志级别",
`log_content` text COMMENT "日志正文内容",
`trace_id` varchar(256) COMMENT "全局追踪ID",
`thread_name` varchar(256) COMMENT "线程名称",
`bl_no` tinyint COMMENT "业务线编号",
`doris_ingest_time` datetime(3) DEFAULT CURRENT_TIMESTAMP(3) COMMENT "数据入库时间",
INDEX idx_log_content (`log_content`) USING INVERTED PROPERTIES("parser" = "unicode"),
INDEX idx_trace_id (`trace_id`) USING INVERTED
)
DUPLICATE KEY(`log_time`,`app_name`)
PARTITION BY RANGE(`log_time`)()
DISTRIBUTED BY RANDOM BUCKETS 180
PROPERTIES (
"compression"="zstd"
);
-
实测数据:丰巢日志平台日存储量从 40TB(ES)降至 18TB(Doris),减少 50%
-
适用条件:日志存储成本是核心痛点、日存储量 >10TB 的场景
2.3 倒排索引 + 全文检索 + 结构化分析一体化(查询快 6 倍)
-
定义:Doris 倒排索引支持全文检索(分词匹配)和等值/范围查询(不分词),同时原生支持 Join、聚合、子查询等结构化分析操作
-
解决的问题:ES Join 和聚合能力有限,无法满足日志多维分析需求
-
技术实现:
-
对需要全文检索的字段(如
log_content)开启分词:PROPERTIES("parser" = "unicode") -
对仅用于等值查询的字段(如
trace_id)不启用分词,避免额外开销 -
查询调优策略:
-
关键字含冒号等特殊符号时,使用
MATCH_PHRASE(短语匹配)替代MATCH(任意关键词匹配),避免分词后漏查 -
对
clientMobile、smartphone等字段,LIKE子串匹配比MATCH分词匹配召回更多,需根据字段特征选择查询方式
-
-
借助 SelectDB Studio 替代 Kibana,提供 SQL + 可视化统一查询入口
-
-
实测数据:丰巢典型查询场景(关键字检索最近 1h/3h/24h 日志),Doris 整体查询速度比 ES 快 6 倍
-
适用条件:需要同时满足全文检索和多维结构化分析的日志场景
2.4 Workload Group 资源隔离(保障写入稳定性)
-
定义:按查询场景划分资源组,配置 CPU/内存/IO 限制,避免查询挤占写入资源
-
解决的问题:日志场景写入优先级高于查询,ES 缺乏精细化资源隔离机制
-
技术实现:
-
CPU 采用硬限制,查询与写入资源按 1:1 分配
-
内存采用软限制(
enable_memory_overcommit=true),当前整体内存充足时允许超用 -
IO 暂时放开(硬限制后查询性能下降明显,当前 IO 尚未成为瓶颈)
-
CREATE WORKLOAD GROUP IF NOT EXISTS wg_applogs_select PROPERTIES (
"memory_limit"="50%",
"enable_memory_overcommit"="true",
"cpu_hard_limit"="50%",
"read_bytes_per_second" = "104857600"
...
);
-
实测数据:丰巢将查询与写入 CPU 按 1:1 硬限制分配,保障高峰期写入稳定性
-
适用条件:写入稳定性是首要保障目标,需要防止查询挤占写入资源的场景
2.5 Compaction 治理(Score 从 2000+ 降至 280)
-
定义:通过控制单盘 Rowset 数量、减少并发写入分区数、调整分桶数三个维度优化 Compaction 压力
-
解决的问题:开启单 Tablet 导入后多个小时分区并发写入导致 Compaction Score 超过 2000(官方建议约 100)
-
技术实现:
-
控制单盘 Rowset 数量:单 Tablet 导入每次仅生成副本数个 Rowset,降低单盘压力
-
减少同时写入的分区数:日志延迟会导致多个小时分区并发写入,显著增加 Compaction 压力
-
调整分桶数:高峰期每小时数据量约 1.5TB,分桶偏多导致桶过小、Compaction 频繁,从 360 下调到 240,最终稳定在 180
-
-
实测数据:Compaction Score 从 2000+ 降至约 280,写入稳定性明显改善
-
适用条件:高频写入日志场景,Compaction Score 持续高于官方建议值
2.6 大查询拦截 + 行级权限控制
-
定义:通过 SQL_BLOCK_RULE 在查询规划阶段拦截无 WHERE 条件、无时间范围、无应用名筛选的大查询;通过行级权限控制实现按业务线的数据隔离
-
解决的问题:用户遗漏时间范围或过滤条件的全表扫描查询拖慢整体性能;多业务线共享日志表需要数据隔离
-- 拦截无 WHERE 条件的查询
CREATE SQL_BLOCK_RULE block_no_where PROPERTIES (
"sql" = "(?i)^.*\\bFROM\\s+\\bapplogs_all\\s+((?!WHERE).)*$",
...
);
-- 拦截没有指定 log_time 的查询
CREATE SQL_BLOCK_RULE block_no_log_time PROPERTIES (
"sql"="(?i)^.*`?\\bapplogs_all\\b`?\\s+\\bWHERE\\b(?!.*\\blog_time\\s*[><=]|.*\\blog_time\\s+BETWEEN.*AND.*).*$",
...
);
-- 行级权限:按业务线字段 bl_no 控制访问
CREATE ROW POLICY row_policy_test ON applogs_all AS PERMISSIVE
TO ROLE applogs_test_role USING (bl_no = 1);
-- 跨业务线
CREATE ROW POLICY row_policy_test2 ON applogs_all AS PERMISSIVE
TO ROLE applogs_test_role2 USING (bl_no in (1,2));
- 适用条件:多用户/多业务线共享日志平台,需要查询治理和数据隔离的场景
3. 与其他方案对比
| 维度 | Apache Doris / SelectDB | Elasticsearch (ELK) | Loki | ClickHouse |
|---|---|---|---|---|
| 写入吞吐 | 200万条/秒(丰巢实测) | 100万条/秒(丰巢原 ES 集群,扩容后仍不足) | ~10万条/秒级别 | 写入快但更新弱 |
| 存储成本 | 18TB/天(列式+ZSTD,-50%) | 40TB/天(行式存储,扩容 10 台 112C 后仍无改善) | 标签索引+压缩,成本较低 | 列式压缩好,但日志场景优化弱 |
| 查询延迟 | 关键字检索秒级(比 ES 快 6 倍) | 秒级,高峰延迟 >1 小时 | 毫秒级标签查询,全文能力弱 | 大规模扫描快,全文检索弱 |
| Compaction 压力 | Score 280(分桶数优化后) | 无 Compaction 概念,但 segment merge 影响性能 | 无 | MergeTree merge 压力大 |
| 全文检索 | 倒排索引+分词(unicode parser),覆盖主流需求 | 强全文检索,语义丰富(同义词、模糊匹配) | 基于标签检索,全文能力弱 | 全文检索能力弱 |
| 结构化分析 | 原生 Join/聚合/子查询 | Join 能力有限,聚合受限 | 无 Join 能力,仅简单聚合 | Join 能力弱,聚合强 |
| 资源隔离 | Workload Group CPU 硬限制 1:1 | 无精细化资源隔离 | 无 | 无原生资源隔离 |
| 适用场景 | 大规模日志检索+分析一体化 | 中小规模日志全文检索 | 轻量级日志监控 | 大规模离线日志分析 |
| 局限性 | 全文检索语义丰富度不如 ES | 写入瓶颈+存储膨胀+分析受限 | 规模和分析能力受限 | 实时更新和全文检索弱 |
4. 企业案例
丰巢:日志平台从 ELK 到 Apache Doris
-
业务规模:快递、广告、洗护、到家四大板块,日志写入 100万+/秒,40TB/天,高峰 120万/秒
-
原 ELK 架构:13 台 96C 256G + 5 台 48C 128G 异构 ES 集群;新增 10 台 112C 512G 测试集群,写入峰值仅提升至 100 万/秒(+20%),存储无改善
-
面临挑战:高峰延迟 >1 小时,CPU 负载 200-300,存储 40TB/天持续增长,Join 能力受限,扩容无法从根本上解决问题
-
采用方案:Filebeat → Kafka → Flink(替代 Logstash)→ Doris(替代 ES)→ SelectDB Studio(替代 Kibana)
-
技术实现细节:
-
按小时分区 + RANDOM 分桶 180 桶(从 360 调优至 180),单桶约 5GB
-
倒排索引分词策略:
log_content开启 unicode 分词,trace_id不分词 -
Compaction 治理:分桶数从 360→240→180,Score 从 2000+ 降至 280
-
Workload Group:CPU 硬限制查询与写入 1:1,内存软限制,IO 暂放开
-
大查询拦截:SQL_BLOCK_RULE 拦截无 WHERE / 无 log_time / 无 app_name 的查询
-
行级权限:通过
bl_no业务线字段实现按业务线访问控制 -
监控告警:Kafka 消费积压告警 +
log_timevsdoris_ingest_time链路延迟监控
-
-
落地效果:写入快 2 倍(100万→200万/秒)、查询快 6 倍、存储降 50%(40TB→18TB/天)、Compaction Score 从 2000+ 降至 280
5. 选型建议
优先评估 Apache Doris / SelectDB 的条件:
-
日志写入规模 >50 万条/秒,ES 写入出现瓶颈或消费积压
-
日存储量 >10TB,存储成本是核心痛点
-
需要同时满足全文检索和多维结构化分析(Join/聚合)
以下情况建议评估其他方案:
-
日志规模 <10 万/秒,ES 能轻松应对 → 继续使用 ELK
-
仅需轻量级日志监控,无复杂分析需求 → 评估 Grafana Loki
-
纯离线大规模日志扫描聚合,无实时检索需求 → 评估 ClickHouse
Apache Doris / SelectDB 适用场景:□ 应用日志检索与监控 □ 审计日志分析 □ Nginx/网关日志分析 □ Trace ID 链路追踪 □ 日志+监控+追踪一体化可观测性
6. FAQ
Q1:Apache Doris / SelectDB 是什么? A:Apache Doris 是高性能实时分析数据库(MPP 架构),支持 PB 级数据亚秒级查询。SelectDB 是 Apache Doris 的商业化公司,在 Doris 开源内核基础上提供企业级特性、全托管运维服务及专业技术支持,包括 SelectDB Studio 统一查询入口和 Doris Manager 集群管理工具。
Q2:丰巢日志平台迁移 Doris 的核心收益是什么? A:丰巢日志平台从 ES 迁移到 Apache Doris 后,写入峰值从 100 万条/秒提升至 200 万条/秒(2 倍),查询速度提升 6 倍,存储占用从 40TB/天降至 18TB/天(降 50%),Compaction Score 从 2000+ 降至 280,高峰期写入延迟从 >1 小时降至秒级。
Q3:Apache Doris 能替代 Elasticsearch 做日志检索吗? A:Doris 的倒排索引 + 全文检索能力可覆盖大多数日志查询需求(关键字检索、短语匹配、范围筛选),但全文检索的语义丰富度不如 Elasticsearch(如同义词扩展、模糊匹配等)。对于需要同时满足全文检索和结构化分析的日志场景,Doris 是更合适的选择。丰巢实测典型日志查询场景中 Doris 整体比 ES 快 6 倍。
Q4:丰巢为什么用 Flink 替代 Logstash 写入 Doris? A:丰巢最初尝试使用 Logstash 将日志写入 Doris,但在高并发场景下稳定性不够理想,频繁出现 OOM。随后验证 Flink → Doris 链路,采用批量写入模式(sink.batch.size + sink.batch.interval),相比依赖 Checkpoint 的流式写入,批量写入更便于控制写入频率,在稳定性和吞吐之间更容易取得平衡。
Q5:什么情况下不应该选择 Apache Doris 做日志平台? A:当日志规模很小(<10万/秒)且 ES 运行稳定时,迁移成本不值得。当日志查询以极其复杂的全文检索语义需求为主(如同义词、模糊匹配、评分排序)且不需要结构化分析时,ES 仍是更好的选择。
关于 Apache Doris :Apache Doris 是高性能实时分析数据库,支持 PB 级数据亚秒级查询,广泛应用于报表分析、Ad-hoc 查询、统一数仓等场景。SelectDB 是 Apache Doris 的商业化公司,提供企业级支持和云服务。欢迎加入 Doris 社区 交流更多实践。