恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
Apache Doris 在可观测性场景下的性能优势与实战调优
首页
资讯中心
/
Apache Doris 在可观测性场景下的性能优势与实战调优
Apache Doris 在可观测性场景下的性能优势与实战调优
发布时间:2026/8/12 23:11:44
1. 项目概述当可观测性数据遇上实时分析引擎最近在搞可观测性平台的数据层选型团队里几个兄弟为了日志和指标数据的存储分析方案吵得不可开交。Elasticsearch 是老牌选手查询灵活但面对海量写入和复杂聚合时资源开销和成本让人头疼ClickHouse 在分析性能上是个狠角色但它的数据更新和实时关联查询能力在处理 Agent 上报的、带状态的复杂日志流时总感觉有点“水土不服”。就在我们纠结的时候一个内部压测项目的结果引起了我的注意在模拟真实 Agent 可观测性数据我们内部称之为 AgentLogsBench的生产负载测试中Apache Doris 的表现相当抢眼不仅在吞吐和延迟上领先其架构特性与可观测性场景的需求契合度之高让我觉得有必要深入聊聊。简单来说这个测试的核心就是用一个接近真实生产环境的基准去“折腾”各个分析型数据库看谁能更好地承接来自成千上万台服务器上 Agent 实时上报的日志、指标、链路数据并支撑业务人员即席的、多维的交互式分析。结果Apache Doris 跑出来了。这不仅仅是一个性能数字的胜利更深层次的原因是Doris 的某些设计哲学恰好命中了现代可观测性数据处理的几个关键痛点高并发实时写入、宽表与多表关联分析并存、对新鲜数据的极低延迟查询需求以及在大规模部署下对运维成本的控制。如果你也在为微服务或云原生环境下的可观测性数据栈选型或者正在被 Elasticsearch 集群的扩容成本和 ClickHouse 的查询复杂度困扰那么这次围绕 AgentLogsBench 的实践与发现或许能给你提供一个值得认真考虑的新选项。接下来我会结合测试中的发现和我们自己的评估实践拆解 Doris 为何能在这个场景下表现突出以及在实际落地时你需要关注的那些细节和“坑”。2. 可观测性数据负载的独特挑战与测试基准设计在深入技术细节之前我们得先搞清楚来自 Agent 的可观测性数据负载到底给数据库提出了哪些非常规的挑战。这决定了为什么一个通用的 OLAP 引擎可能不够而需要针对性的优化。2.1 Agent 数据流的四大核心特征首先Agent如 Prometheus Node Exporter, OpenTelemetry Collector, 或各类商业 Agent产生的数据流有其鲜明特点高吞吐、流式写入成千上万的服务器、容器实例持续不断地产生日志和指标。数据是 7x24 小时不间断的流写入压力稳定且巨大要求数据库具备极高的写入吞吐能力并且写入不能阻塞或严重影响并发查询。数据热度过山车新产生的数据比如最近 5 分钟被查询的概率极高用于实时告警和故障排查。随着时间的推移数据的查询频率急剧下降但基于合规或历史分析需求又需要长期保存。这要求存储系统具备高效的热冷数据分层管理能力。schema 灵活与半结构化日志数据往往是半结构化的 JSON 或文本字段可能动态增加。指标数据虽然结构相对固定但维度标签组合可能非常丰富。这要求系统既能处理灵活的 schema又能对结构化部分进行高效的列式存储和编码。复杂的查询模式查询很少是简单的点查。它通常是多维的时间范围过滤是必选项然后结合多个标签如service‘order’,host‘192.168.1.1’,level‘ERROR’进行筛选、分组聚合如按错误类型统计次数、排序如找出耗时最长的 API 调用有时还需要进行多表关联如将链路 Trace 数据与错误日志关联。2.2 AgentLogsBench 基准测试解析为了公平地衡量不同系统我们设计的 AgentLogsBench 基准主要模拟了以下负载数据模型包含两张核心表。一张是agent_logs宽表模拟典型的应用日志包含时间戳、服务名、主机 IP、日志级别、线程 ID、动态的 JSON 字段存放具体日志内容以及从 JSON 中提取的常用字段如error_code,duration_ms。另一张是agent_metrics模拟指标数据包含时间戳、指标名、多组维度标签Key-Value 对和数值。写入负载使用多个写入客户端模拟数百个 Agent 实例以恒定速率向系统写入数据。重点考察系统的峰值写入吞吐MB/s 或 条/秒、写入稳定性延迟是否抖动以及写入对集群资源的消耗。查询负载设计了一套混合查询模板Query Template包括近期数据高频点查查询特定服务、主机在最近 1 分钟内的错误日志。时间范围扫描与聚合统计过去 1 小时内各服务的错误日志总数、平均响应耗时。多维度下钻分析按服务、主机、错误代码等多个维度进行分组、排序和分页查询。宽表与 JSON 字段查询对动态 JSON 字段中的特定属性进行过滤和提取。表关联查询将agent_logs中的异常请求与agent_metrics中同一时间段的系统资源指标如 CPU 使用率进行关联分析。评价指标核心看三点查询响应时间P99 Latency、系统吞吐QPS以及资源利用率CPU/Memory/Disk IO。目标是追求在有限的硬件资源下获得更低的查询延迟和更高的并发处理能力。这个基准的意义在于它不是一个单纯的“跑分”工具而是将可观测性场景下的典型压力抽象成可重复的测试用例从而更真实地反映引擎在生产环境中的潜力。3. Apache Doris 的核心架构优势解读为什么 Doris 能在这样的测试中表现突出这需要从其架构设计上找原因。Doris 是一个 MPP大规模并行处理架构的、基于 MySQL 协议的实时分析数据库。它在设计之初就融合了 Google Mesa 和 Apache Impala 的思想针对现代实时分析场景做了大量优化。3.1 高并发写入与数据组织面对 Agent 数据流的高并发写入Doris 的解决方案非常直接有效。写入链路优化Doris 的写入分为几个阶段。数据首先通过 FEFrontend进行协议解析和路由然后被分发到对应的 BEBackend节点。BE 节点在内存中会维护一个 MemTable 用于快速接收数据并定期或根据大小阈值 Flush 成不可变的磁盘文件Segment。这个过程类似于 LSM-Tree但做了大量简化。最关键的是Doris 支持Batch Delete和Upsert语义这对于修正或删除 Agent 误报的数据非常有用而这是 ClickHouse 的 MergeTree 引擎相对棘手的部分。数据分区与分桶Partition Bucket这是 Doris 数据组织的精髓。对于agent_logs表我们通常会按时间进行分区例如按天分区PARTITION BY RANGE(dt)。这样做有两个巨大好处第一对于时间范围的查询可以快速定位到相关分区避免全表扫描第二便于管理数据生命周期可以轻松地删除或归档历史分区如保留 30 天。在每个分区内数据还会通过DISTRIBUTED BY HASH语句进行分桶将数据打散到多个 BE 节点上。合理的分桶键选择例如service_name, host_ip可以确保数据均匀分布并且让涉及这些键的查询能够进行本地化计算减少网络 Shuffle极大提升聚合和过滤性能。实操心得分桶键的选择是性能关键分桶键的选择需要权衡数据均匀性和查询模式。如果只按host_ip分桶当查询只按service_name过滤时就需要跨桶进行数据聚合。一个常见的做法是选择 2-3 个最高频的过滤或分组字段作为组合分桶键。在我们的场景中(service_name, host_ip)是一个不错的选择。分桶数量建议控制在每个 BE 节点 10-100 个之间太少会导致并行度不够太多会增加元数据开销。3.2 向量化执行引擎与物化视图这是 Doris 查询速度快的“秘密武器”。向量化执行引擎传统的数据库执行引擎是逐行处理Row-by-Row每次操作都要处理大量的函数调用和条件判断开销。Doris 的向量化引擎则将数据按列组织成批Batch在 CPU 的缓存中进行连续操作。对于分析型查询中大量存在的扫描、过滤、聚合操作这种模式能极大地利用现代 CPU 的 SIMD单指令多数据指令集实现成倍的性能提升。在 AgentLogsBench 的聚合查询中向量化引擎的优势被充分释放。物化视图Materialized View这是应对可观测性场景中“固定模式分析”的利器。例如业务经常需要查询“过去5分钟各服务的错误率”。如果每次都对原始亿级日志表进行GROUP BY计算代价很高。我们可以在agent_logs表上创建一个物化视图预先按照dt天、service_name、level进行聚合计算好count和sum(duration_ms)。当用户查询匹配这个聚合模式时Doris 的查询优化器会自动路由到物化视图上读取已经计算好的聚合结果查询速度可以从秒级提升到毫秒级。Doris 的物化视图是自动增量更新的对用户透明维护成本很低。-- 创建物化视图的示例 CREATE MATERIALIZED VIEW service_error_stats AS SELECT dt, service_name, level, count(*) as log_count, sum(duration_ms) as total_duration FROM agent_logs GROUP BY dt, service_name, level;3.3 灵活的索引与数据湖分析前缀索引与 Bloom FilterDoris 的表数据存储在 Segment 文件中每个 Segment 会为前 36 个字节自动生成一个前缀索引。如果查询条件包含这些列可以快速定位数据块。对于其他列和等值查询可以创建Bloom Filter 索引它能以极小的空间代价快速判断一个数据块中是否包含某个值从而在扫描时跳过大量不相关的数据块。对于agent_logs表中的host_ip,trace_id这类高基数列的等值查询Bloom Filter 效果显著。与数据湖的联邦查询可观测性数据并非全部需要实时分析大量冷数据可以存储在更便宜的对象存储如 S3、OSS中。Doris 支持通过Multi-Catalog功能直接对接 Hive、Iceberg、Hudi 等数据湖格式或者通过 JDBC 连接外部数据库。这意味着你可以制定这样的策略最近 7 天的热数据存放在 Doris 本地 SSD 上提供极致查询体验7 天到 1 年的温数据存放在对象存储如通过 Apache Iceberg 管理Doris 可以联邦查询1 年以上的数据归档。这样实现了成本与性能的最佳平衡这个架构与可观测性数据的热度衰减特性完美匹配。4. 基于 AgentLogsBench 的实战配置与调优纸上得来终觉浅我们来看看在 Doris 上具体如何搭建一个能扛住 AgentLogsBench 测试的集群和表结构。4.1 集群部署与表结构设计假设我们有一个中等规模的集群3个 FE1个 Leader2个 Follower用于高可用和元数据管理6个 BE 用于数据存储和计算。所有节点混合部署磁盘使用 SSD。建表示例是重中之重-- 创建日志宽表 CREATE TABLE agent_logs ( ts datetimev3 NOT NULL COMMENT 日志时间戳, service_name varchar(50) NOT NULL COMMENT 服务名, host_ip varchar(15) NOT NULL COMMENT 主机IP, pod_name varchar(100) COMMENT Pod名称, log_level varchar(10) NOT NULL COMMENT 日志级别, thread_id int COMMENT 线程ID, raw_json string COMMENT 原始JSON日志, extracted_error_code varchar(20) COMMENT 从JSON提取的错误码, extracted_duration_ms int COMMENT 从JSON提取的耗时(ms), dt date NOT NULL COMMENT 日期分区列由 ts 生成 ) ENGINEOLAP DUPLICATE KEY(ts, service_name, host_ip, log_level) -- 重复模型适合日志 PARTITION BY RANGE(dt) ( PARTITION p20240501 VALUES [(2024-05-01), (2024-05-02)), PARTITION p20240502 VALUES [(2024-05-02), (2024-05-03)) -- ... 后续分区可以通过动态分区特性自动创建 ) DISTRIBUTED BY HASH(service_name, host_ip) BUCKETS 48 PROPERTIES ( replication_num 3, -- 副本数保障高可用 storage_medium SSD, dynamic_partition.enable true, -- 启用动态分区 dynamic_partition.time_unit DAY, dynamic_partition.start -7, -- 保留最近7天分区 dynamic_partition.end 3, -- 提前创建未来3天分区 dynamic_partition.prefix p, bloom_filter_columnshost_ip,extracted_error_code,trace_id -- 创建BloomFilter索引 ); -- 创建物化视图加速按服务和级别的聚合查询 CREATE MATERIALIZED VIEW mv_log_stats_by_service_level AS SELECT dt, service_name, log_level, count(*) FROM agent_logs GROUP BY dt, service_name, log_level;关键配置解析数据模型选择我们选择了DUPLICATE KEY模型。对于日志数据每条记录都是独立的没有唯一主键的概念且我们可能需要保留完全相同的多条日志。DUPLICATE KEY模型最适合这种场景它按照指定的排序列ts, service_name...进行排序相同前缀的数据在物理上会更接近利于范围查询。动态分区dynamic_partition相关属性是运维神器。它自动管理分区的创建和删除比如每天自动创建明天的分区并删除7天前的分区完全免去了手动维护分区的工作。分桶数BUCKETS 48。我们计划将数据分布在6个BE上每个BE上该表会有8个桶。这个并行度对于我们的查询和集群规模是合适的。分桶数最好是 BE 节点数的整数倍以保证数据均匀。4.2 写入优化与 Compaction 调参高并发写入下需要关注 BE 的内存和 Compaction数据压缩合并策略。Stream Load 与 Routine Load对于 Agent 数据推荐使用Stream LoadHTTP API进行微批写入如每批 100MB 或 10万条。它的吞吐高协议简单。Doris 也支持Routine Load通过订阅 Kafka 等消息队列自动导入数据更适合与流处理管道集成。在 AgentLogsBench 测试中我们使用多客户端并发 Stream Load 来模拟压力。内存与 Compaction 配置写入性能的瓶颈常常在 Compaction。如果数据写入太快而底层文件的合并速度跟不上就会产生大量小文件影响查询性能。需要调整 BE 的配置参数# 在 be.conf 中调整 # 提高单个Compaction任务的内存上限加速合并过程 compaction_task_num_per_disk 4 compaction_worker_threads 8 # 调整各层级的Compaction策略控制文件大小和合并频率 cumulative_compaction_num_threads_per_disk 2 base_compaction_num_threads_per_disk 1注意事项写入与查询的资源隔离在高并发写入期间Compaction 会消耗大量 CPU 和 IO 资源可能影响查询性能。在生产环境中可以考虑将集群的 BE 节点分为两组一组专门负责接收写入和 Base Compactionwrite_group另一组专门负责查询和 Cumulative Compactionquery_group。通过 Doris 的 Tag 功能可以将表的不同副本分布到不同组别的节点上实现物理资源的隔离。这是应对极端写入负载的高级策略。4.3 查询性能调优实战即使有了好的表结构查询也可能因为姿势不对而变慢。以下是一些实战技巧利用分区裁剪确保你的查询条件中总是包含分区列dt。例如WHERE dt2024-05-01 AND ts BETWEEN ...。这样 Doris 在规划阶段就能直接跳过无关分区。**避免 SELECT ***明确列出需要的列。特别是raw_json这种大字段除非必要否则不要 select 出来。Doris 是列存只读取需要的列能极大减少 IO。善用物化视图分析常用的查询模式为其创建物化视图。Doris 优化器会自动选择无需修改查询语句。监控与诊断使用EXPLAIN命令查看查询执行计划。重点关注是否有SCAN全表、AGGREGATE是否在本地进行、是否有不必要的SHUFFLE。Doris 的 Web UI 也提供了直观的查询 Profile可以定位到耗时最长的算子。5. 典型问题排查与运维心得在实际运行和测试中我们踩过一些坑也总结了一些经验。5.1 常见问题速查表问题现象可能原因排查步骤与解决方案写入失败报错Tablet writer add batch unknown errorBE 节点内存不足或单个 Tablet 写入过于频繁。1. 检查 BE 节点内存使用top命令。2. 增加 BE 的write_buffer_size或降低导入批次大小。3. 检查表的分桶是否合理如果数据严重倾斜导致单个 Tablet 过热需要调整分桶键。查询速度突然变慢1. 存在大量小文件未合并。2. 集群负载不均衡某个 BE 节点成为热点。3. 查询未命中分区或索引。1. 执行SHOW PROC /compaction查看 Compaction 状态和积压情况。2. 执行SHOW PROC /backends查看各 BE 的负载磁盘使用率、扫描行数。3. 使用EXPLAIN分析慢查询确认是否扫描了过多分区。磁盘空间增长过快1. 数据保留策略未生效。2. 副本数设置过高。3. 导入了大量临时测试数据。1. 检查动态分区配置dynamic_partition.end是否生效手动执行ALTER TABLE ... DROP PARTITION ...删除历史分区。2. 评估replication_num是否可从 3 降为 2需权衡可用性。3. 清理无用数据并考虑开启 ZSTD 等更高压缩比的压缩算法。FE 出现bdbje相关错误FE 元数据存储BDB JE出现异常可能是磁盘满或文件损坏。这是严重问题立即检查 FE 日志和磁盘空间。确保 FE 元数据目录有独立、可靠的磁盘。定期备份元数据。5.2 容量规划与成本考量对于可观测性场景容量规划至关重要。一个简单的估算公式总原始数据量 per day 单台服务器日志量 × 服务器数量 × 副本数假设单台服务器每天产生 10GB 日志有 1000 台服务器采用 3 副本那么每天新增的原始数据存储需求就是 30TB。Doris 的列存压缩比通常在 5:1 到 10:1 之间我们按 5:1 估算那么每天需要约 6TB 的物理磁盘空间。这只是热数据比如最近7天的本地 SSD 成本。更早的数据可以沉降到对象存储成本会大幅下降。成本控制的核心思路数据分层利用 Doris 2.0 的冷热数据分层功能将冷数据自动迁移到对象存储。压缩算法在创建表时指定compression zstd可以获得比默认 LZ4 更高的压缩比节省存储空间但会略微增加 CPU 开销。降副本数对于可容忍一定故障风险的测试或非核心环境可以将replication_num设为 2。按需升配初期可以采用较小规模的集群随着数据量增长通过增加 BE 节点进行水平扩容这个过程在 Doris 中是在线的相对平滑。5.3 与 Elasticsearch/ClickHouse 的对比思考最后谈谈我们为什么在 AgentLogsBench 后更倾向于 Doris而不是另外两个流行选择vs ElasticsearchES 的强项在于全文检索和灵活的 JSON 查询。但对于大规模、高基数的数值聚合分析其资源消耗尤其是内存巨大查询延迟也更高。Doris 在纯分析场景下的性能和资源效率优势明显且 SQL 生态对分析师更友好。如果业务强依赖全文检索如日志关键词模糊匹配可以考虑 Doris 对接 ES 进行联邦查询或者使用 Doris 的倒排索引功能仍在完善中。vs ClickHouseClickHouse 是性能怪兽在单表聚合分析上甚至可能略胜一筹。但它的短板也明显1) 集群管理相对复杂需要自行处理分片和副本2) 对高频数据更新和删除MergeTree 的ReplacingMergeTree/CollapsingMergeTree语义最终一致支持不如 Doris 的Unique Key/Aggregate Key模型直观和实时3) 多表关联性能是弱项。Doris 提供了更接近传统数据库的使用体验更完善的 SQL 支持如窗口函数、更易用的物化视图和更简单的集群运维在可观测性这种需要灵活关联和实时修正的场景下整体体验更均衡。我个人在实际测试和预生产环境验证中的体会是Apache Doris 提供了一个在性能、功能、易用性和运维成本之间取得出色平衡的选项。它可能不是每个单项的“冠军”但作为支撑 Agent 可观测性生产负载的“全能选手”其综合得分非常高。特别是对于已经熟悉 MySQL 协议和生态的团队它的上手门槛很低而性能上限又能满足绝大多数企业的实时分析需求。当然没有银弹最终选型还是要结合自己团队的技术栈、具体的查询模式和运维能力来决定。至少在下次进行数据平台技术选型时你的清单里应该给 Apache Doris 留一个重要的位置。