<p>在当前银行业务全面线上化、实时化的驱动下,浙江省头部城商行亟需构建一个能够同时承载海量数据加工与高并发实时查询的数据平台,以支撑精准营销、实时风控和智能决策等关键业务。</p>
在这一数字化转型进程中,我们最终引入了 Apache Doris 作为湖仓一体架构的核心组件。Doris 凭借其卓越的查询性能、高吞吐、对标准 SQL 的完整支持以及高效的实时数据摄入能力,在多个候选方案中脱颖而出。尤其值得一提的是,其架构的灵活度及可扩展性、极大降低了运维难度和成本投入。截至目前,我们已顺利完成 200TB+ 历史数据的平滑迁移与落地,为后续的深度应用奠定了坚实基础。
然而,在实践过程中,“算”(批量数据处理)与“查”(业务实时查询)这两种负载在资源需求与业务目标上的根本性矛盾逐渐凸显,解决这一矛盾已成为当下首要目标。
核心矛盾:“算”与“查”的资源争抢
当“计算”和“查询”共用一个 Doris 集群时,资源争抢问题十分突出。例如,批量计算任务会在短时间内会占用大量 CPU、内存和 IO 资源,集群负载骤升,直接影响同时运行的业务查询的稳定性。其根本原因在于:
- “算”的核心是吞吐量与任务交付。数仓专注于大规模数据的批量加工(如ETL、数据清洗与聚合计算),需要在有限资源下高效处理TB/PB级数据,确保任务在业务时间窗口内完成。其关键指标是任务成功率与产出时效,而对单个任务的响应时间并不敏感,只要能在业务允许的时间窗口内交付结果,即便耗时数小时亦可接受。
- “查”的核心是响应速度与服务可用性。它直接面向一线业务端(如实时风控、客户画像、经营报表),通常是对数仓加工后的结果数据进行即时查询,对查询响应速度和高可用有着严格要求——业务人员往往需要在秒级甚至毫秒级获取查询结果,且不能出现因集群问题导致的查询中断,否则会直接影响业务正常运转。
解决方案:查算分离架构设计
正因如此,我们意识到,要兼顾数据仓库“计算”的效率与业务“查询”的性能,“查算分离”架构是必然之选。该架构旨在将“计算”和“查询”的负载拆分到不同的集群中,使它们在各自专属的资源环境下运行。这样既能够充分发挥数据仓库的计算能力,又能确保业务查询的响应时间和稳定性。
结合上图所示的存算分离架构,我们通过以下四个方面的设计,系统性地实现了查算分离目标:
- 查询低延迟保障: 为确保查询的低延迟,在 Doris 中部署了独立的查询集群,实现与计算集群的物理资源隔离,从根本上避免批量任务对线上查询的干扰。
- 数据实时同步: 为打通计算与查询集群之间的数据链路,引入跨集群数据复制功能 CCR,实现表级数据的近实时同步。CCR 基于 Doris Binlog 的增量物理复制机制,可确保数据产出后快速同步至查询集群,且不影响线上查询性能。基于该能力,已成功上线 500 张表、30TB 数据, 在跑批高峰期主从延迟也能控制在 15 分钟内。
- 高可用与容灾: 我们构建了双集群热备体系,日常将 95% 的查询流量导向查询集群,5% 流量分流至计算集群。通过持续的流量压测,确保两集群随时具备故障切换能力。
- 成本投入控制: 在保障查询性能的前提下,为控制整体投入,我们在计算集群中创建了与查询集群规格相近的 Workload Group(查询 WG),并设置资源软限制策略,允许 ETL 任务弹性复用其闲置资源。该设计在常态下显著节约资源,尽管极端故障场景下全量切流可能引发短暂性能波动,但发生概率极低,风险整体可控。
优化实践:性能提升百倍、 CPU 消耗仅 10%
查询性能优化向来就是一个复杂的课题,它与 SQL 语句写法、数据量的大小、建表的设计等多个因素共同影响,难以一蹴而就。在业务从原有系统迁移至新环境时, 我们暂未针对 Doris 进行优化,因此在业务上线初期遭遇性能挑战:集群 QPS 仅维持在 10 左右,而 CPU 消耗却高达 90%。这样的表现显然无法满足业务正常运转的需求。
为此,我们从分区裁剪、记录过滤、并发执行和查询结果获取这四个维度进行全面的优化。优化后,查询性能相比之前提升百倍;在相同负载下,集群 CPU 消耗从 90% 下降到 10% 内,效果十分显著。在这次优化过程中,积累了不少实用经验,在此分享给大家。
01 拆分查询 SQL 、优化分区裁剪,查询性能提升 6 倍
下方代码块展示了我们最常见的 SQL 模板,其典型特征是根据 etl_job_flag 表中记录的数据产出时间筛选最新的业务数据。由于分区字段 data_dt 的查询条件是一个子查询,导致 Doris 在执行时无法动态裁剪分区,只能扫描所有历史分区,从而产生大量无效 IO。
我们对其进行了优化,首先将查询 SQL 拆分成两条 SQL 语句,先获取数据产出时间,再查询目标数据。其次将分区字段 data_dt 的条件调整为常量,限制其只扫描一个分区。通过该优化,实现了查询性能 6 倍的提升。
// 原始 SQL
select * from t where data_dt = (select max(data_dt) from etl_job_flag wehre etl_table="t") and 其他过滤条件
// 优化后 SQL
select max(busi_dt) from etl_job_flag where etl_table="t"
select * from t where data_dt = xxx and 其他过滤条件
02 合理设计 Key 和索引,查询性能提升 6-7 倍
Doris 的记录过滤遵循“成本从低到高”的顺序,依次为 Key Range 、索引过滤、 ZoneMap 和 BloomFilter 等轻量级过滤,最后执行谓词评估。由此可知,合理设计 Key 和索引是提升筛选效率的关键。在实践中,通过补充合适的 Key 和索引,查询性能获得 6-7 倍的提升。
以用户信息表 user_info 为例:
- 将高频查询字段
user_id设为 Unique Key 和分桶字段,以利用 Key Range 快速定位数据范围。 - 对次高频查询字段
user_name建立倒排索引,提高查询效率。 - 控制分桶大小在 1G~10G,减少 segment 文件数量,提升倒排索引查询速度(Doris 每个 segment 文件对应独立的倒排索引)。
03 参数调试, 查询吞吐率提升 2-3 倍
高并发和低响应时间是查询集群的核心需求,适当调整 Doris 的执行相关参数可有效提升查询吞吐量
parallel_pipeline_task_num:Pipeline task 是 Doris 执行调度的基本单元,parallel_pipeline_task_num决定了单个查询的最大并发度。该参数的默认值为 0,即 BE CPU 核心数的一半。num_scanner_threads:Scan 算子负责数据扫描,为 Pipeline task 提供数据。num_scanner_threads是单个 Scan 算子一次性提交到 Scan 线程池的任务数量,它直接影响查询扫描数据的并发度。该参数默认值也为 0,动态计算。
如果将两个参数的默认值设置为高值,可能导致单一查询占用过多资源,进而引发 CPU 缓存污染。根据实际应用经验以及测试结果,建议可将 parallel_pipeline_task_num 设置为 8,将 num_scanner_threads 设置为 2,查询吞吐率可提升 2 – 3 倍。此处作为参考,具体数值可根据实际业务情况来调整。
04 开启行存、降低 IO 开销,查询性能提升 30%
在业务中,如果存在大量 SELECT * 的全列查询,Doris 将默认采用按列存储的方式,该方式需要读取所有列并拼接成行返回。而对于字段较多的表,这并不是最佳处理方式,会导致极高的 IO 成本。
因此,我们在建表或修改表时配置 "store_row_column" = "true",开启行存模式。避免了多列拼接的额外开销,查询性能提升约 30%。
优化利器:慢查询监测 + 性能压测
01 报表 + Profile,全局观测慢查询
在性能优化中,慢查询监测为我们提供了关键的数据洞察。通过对慢查询的持续追踪与分析,我们能够快速定位根因、实施针对性优化,并最终验证策略的有效性,确保我们的工作始终朝着正确的方向推进。

作为监控集群查询状态的核心入口,查询报表在全局观测中扮演着重要角色。它基于审计日志(Audit log)及其他系统表构建,包括慢查询榜单、响应时间统计和错误统计等信息。
Doris Profile 能够详细记录查询执行的统计信息,包括执行计划、每个算子的耗时和数据扫描量等,为定位查询性能问题提供了关键依据。Doris 默认的 Profile 存储机制是保存在内存中,默认保留 500 个;而我们因业务需求,需对 3 天内历史查询问题进行保留,以便问题追溯。因此,我们基于 Doris Profile 开发了 Profile 归档服务。
具体工作原理为:当查询报表识别出慢查询时,Profile 归档服务会自动从 Doris 集群下载对应的 Profile 文件并保存至本地,同时生成专属的 HTTP 链接。管理员在浏览慢查询报表时,只需点击链接,即可直接查看对应的完整 Profile,无需担心因内存中 Profile 被清理而失去关键诊断信息,从而显著提升历史问题追溯的效率。
我们已在集群全局启用 Profile 功能,并将 auto_profile_threshold_ms 设置为 1000ms,这意味着所有执行时长超过 1 秒的查询都会自动记录 Profile,为后续分析提供充分的诊断依据。
查询报表与 Profile 的联动,构建了一套高效的性能优化闭环。一旦集群出现异常,报表会通过内部 IM 自动告警,管理员随即针对慢查询榜单,借助 Profile 进行深度分析、精准定位瓶颈。整个过程形成了从发现问题、精准定位到解决跟踪的完整闭环。
02 查询压测工具,容量评估模拟器
此外,我们基于 Python 开发了查询压测工具,用于上线新业务、扩容集群或优化配置之前,准确评估 Doris 集群的承载能力。
其设计理念是还原真实负载:从 Doris Audit log 中提取历史查询记录,通过多线程随机回放的方式,模拟生产环境中的实际查询压力。在压测过程中,工具会实时统计查询吞吐量、响应时间分布等关键指标。通过这些数据,我们能够评估集群的容量上限,或验证优化措施的有效性,为集群的资源规划与架构调整提供重要依据。
结束语
通过以上优化,Doris 查询集群不仅实现了每日超 700 万次查询的稳定运行,99.95% 的查询响应时间均在 1 秒以内,更在压测中达到了 1500 QPS,充分验证了其已具备支撑实时查询的高性能与高稳定性,为 Doris 在湖仓一体平台中深度应用中扫清关键障碍。
</div>