快手 AB 指标生产场景从 Spark 切换到 Doris:提速 145 倍、资源降 72%,刷新集群规模记录

📅 2026/7/8 22:52:20 👁️ 阅读次数 📝 编程学习
快手 AB 指标生产场景从 Spark 切换到 Doris:提速 145 倍、资源降 72%,刷新集群规模记录

AB 指标计算链路的性能与成本压力

快手 AB 实验平台是公司级指标计算底座,服务全公司业务线,支撑公司级业务决策。在 Spark 时代,AB 指标计算面临计算慢和成本高的问题。以核心指标模板为例,单链路计算耗时约 21 分钟,业务决策被迫延后;在 100% 流量推全场景下,计算成本随实验数量增长线性上升。

基于此,团队将生产链路从 Spark 迁移到 Doris。目前,快手 Doris AB 集群规模包括 5 个 FE 节点、2000 个 BE 节点、10 万 CU、数百 TB 内存池,并划分为 12 个逻辑计算组。近 14 天审计中,集群承载数百万个任务,日均任务量达几十万级,扫描数据量达 40TB、千亿级行。在这一规模下,需从多个层面系统优化。

为什么 Doris 比 Spark 更适合该场景?

Doris 相比 Spark 的优势源于三方面执行模型差异。一是 Pipeline 执行引擎减少线程等待,Spark 在 Shuffle 时数据需落盘,下游线程阻塞,而 Doris 可让出线程执行其他任务,减少 CPU 空转;二是向量化执行提升批处理效率,Spark SQL 用行式 Internal Row,Doris 是全链路列式 Block,更适合 CPU SIMD 批量处理;三是 C++ 运行时降低 JVM 相关开销,Spark 运行在 JVM 上有 GC 和 JIT 开销,Doris 用 C++ 编译后的机器码执行,启动后执行效率高。

对于快手 AB 指标计算,更大收益来自业务计算模型与 Doris 执行机制的匹配。因 AB 指标计算模板长期稳定,团队围绕执行链路深入优化,最终实现 145 倍性能提升。

关键优化:从减少数据流动到压缩计算热路径

完成引擎迁移后,团队围绕 AB 指标计算模板特点,对数据分布、执行计划等进行针对性系统优化。AB 指标计算链路输入固定为累计分流表和指标宽表,输出按实验、分组、桶等维度聚合,结果集一般为百行到万行。完整计算过程主要包括四步,其中第二步和第三步是优化主战场。

该场景特点是 Join Key 长期固定为 UID,聚合维度相对稳定,具备持续专项优化条件。

存储优化:用 Colocate Join 消除跨节点 Shuffle

核心优化是 Colocate Join,其思路是在数据写入阶段按 UID 对数据哈希分桶,使相同 UID 数据落在同一机器、同一分桶内。这样查询时,分流表和行为表可在本地完成 Join,无需跨节点 Shuffle 或搬运大量数据,大部分数据在本地节点内消化,网络只传输少量结果集。

落地 Colocate Join 需保证建表按 UID 哈希分桶,参与 Join 的两张表分桶数严格一致。表结构调整后,需通过 `EXPLAIN` 检查执行计划,只有出现 `Colocated` 才说明优化生效。

计算优化:降低去重聚合与 UDF 热路径开销
Local Distinct Grouping Sets:减少全局 Shuffle

Colocate 优化消除了 Join 的跨节点 Shuffle,但去重算子仍可能引入全局 Shuffle 开销。在 AB 指标计算中,SQL 广泛使用 _Grouping Sets_ ,Doris 原生执行框架无法覆盖 _Grouping Sets + Distinct_ 组合场景,会触发全局 Shuffle。

团队设计并实现了 Local Distinct Grouping Sets 改写机制,将去重计算前移至各计算节点本地执行,先完成局部 Distinct,再进行全局聚合汇总,降低 Shuffle 成本。该优化有透明改写和显式调用两种模式。

不过,这项优化并非在所有场景都优于原执行计划,对于原生 `COUNT DISTINCT` 场景,改写为 Local 模式会引入约 6 秒的 Barrier 等待开销。因此,更适合 Shuffle 成为主要瓶颈的场景,是否启用需结合 Profile 和实际执行计划判断。

UDF Native 化:压缩 CPU 热路径成本

AB 实验链路中,分流判定 UDF 是核心计算逻辑之一,虽单次调用计算开销小,但因数据规模大,成为典型的 CPU 热路径。通过 Profile 分析,Java UDF 占约 80% CPU 开销,主要瓶颈来自 JVM 调用与对象创建开销。

团队将其改写为 C++ Native UDF,消除 JNI 调用成本,并深入 STL 层优化,包括字符串拼接、实验配置访问和用户对象构造等方面。最终,三项优化叠加使 AB 实验模板整体执行性能提升约 3 倍。

调度优化:用隔离、反压和优先级保障 SLA

当 Doris 承载规模扩展到数十万级日任务后,需引入调度层进行系统级治理。第一层是物理隔离,将 AB 集群拆分为 12 个独立计算组,不同优先级业务在不同计算组运行,资源配额独立控制,避免跨业务干扰。第二层是组内控制,在单个计算组内叠加并发上限控制、上游反压机制和优先级队列调度,保障单组稳定性。

物理隔离和组内控制共同保证高优链路在高峰期满足 SLA。

稳定性治理

元数据治理:被动修复到主动治理

Doris FE 作为元数据管理节点,元数据信息保存在 JVM 内存中。生产运行中暴露出单表维度和集群维度两类风险,单表分区规模增长至万级时,FE 生成 Checkpoint 会触发上限约束,导致进程异常退出;Tablet 达到千万级后,FE 元数据对象在堆内累积,Master FE 内存峰值接近 400GB 上限,频繁触发 Full GC。

团队引入元数据容量建模与监控体系,通过统计分析得到单个 Tablet 在 FE 内存中平均占用约 11KB 的经验结论,可提前预测 FE 内存压力。

FE 优化:压缩元数据结构,缩短恢复窗口

团队对元数据结构进行压缩优化,引入 Cloud Table Inverted Index,裁剪 Cloud 场景无用字段,替换部分集合结构,降低对象开销。在百万级 Tablet 压测中,该优化使元数据内存占用从 4.16GB 降至 1.49GB,整体下降约 64%,在千万级规模下,Checkpoint 峰值阶段可节省数十 GB 内存。

针对 FE 运行在超大堆场景,团队对 G1 GC 参数进行针对性调整。调优后,Master FE 的内存峰值由 370 GB 降至 270 GB,24 小时线上验证期间未发生 Full GC。

最后,团队对 FE 启动恢复流程进行并行优化,使整体 FE 恢复窗口缩短至约 10 分钟。这些实践表明,元数据治理应提前纳入系统架构设计。

收益总结:从引擎迁移到计算体系重构

快手 AB 指标生产场景从 Spark 升级到 Doris 性能最大提升 145 倍、资源消耗下降 72%,得益于 Doris 的架构优势和快手基于 Doris 针对 AB 场景的深度优化。

快手 AB 指标生产场景的大规模落地,证明 Doris 适合该场景,为社区提供了基于 Doris 构建 AB Test 平台的最佳实践,还刷新了全球最大单个 Doris 集群规模记录。关于 AB 指标生产和更多应用场景、Doris 落地和优化等主题,欢迎加入 [Doris 社区](https://doris.apache.org/)交流。