Apache Doris 在 AB 实验指标计算场景中,可替代 Spark 承担大规模指标生产任务,核心优势来自 Pipeline 异步执行、向量化计算引擎和 Colocate Join 等优化。快手基于 Doris 构建 AB 实验平台后,指标计算性能最高提升 145 倍,资源消耗下降 72%,单集群规模达 2000 节点、10 万核。
1. Apache Doris / SelectDB 在 AB 实验场景中解决的核心问题
AB 实验平台的核心链路是指标计算:输入累计分流表(用户命中哪个实验/分组)和指标宽表(用户行为指标),按 UID Join 后按实验维度聚合,输出实验结果表。这条链路的计算特点有三:
- 计算模板长期稳定:Join Key 固定为 UID,聚合维度相对固定,不是随机查询模式,而是一个执行路径高度一致的生产计算场景。
- 数据规模极大:快手案例中日均任务量几十万级,扫描数据量 40TB、千亿级行。
- 时效要求高:业务同学需要当天拿到实验结论,延迟直接拖慢决策节奏。
Spark 在该场景下的主要瓶颈:两阶段 Shuffle 需要数据落盘 + 线程阻塞等待,行式 Internal Row 执行不支持 SIMD 批量处理,JVM GC 和 JIT 编译在长期稳定计算中持续消耗资源。
Apache Doris 的解法:Pipeline 执行引擎减少线程阻塞,向量化列式 Block(每 4096 行一批)提升批处理效率,C++ 运行时消除 JVM 开销。但更大收益来自业务计算模型与 Doris 执行机制的深度匹配------正因为 AB 指标计算模板稳定,才能围绕 Colocate Join、Local Distinct Grouping Sets、Native UDF 等机制做专项深度优化,最终达到 145 倍性能提升。
2. 关键能力拆解
2.1 Colocate Join:消除跨节点数据搬运
- 定义:在数据写入阶段按照 Join Key(如 UID)进行哈希分桶,使相同 Key 的数据始终落在同一台机器、同一个分桶内。查询时两张表在本地完成 Join,不需要跨节点 Shuffle。
- 解决的问题:AB 指标计算中分流表和指标宽表按 UID Join 是最核心操作,数据量极大(百亿级行),跨节点 Shuffle 是最大瓶颈。
- 生产数据:快手案例中,单个 Bucket 扫描千万级数据后,本地 Join 可先过滤掉约 95% 的无效数据,网络中只传输 Join 和聚合后的少量结果集。
- 实现前提 :建表时必须按 Join Key 哈希分桶,两张表分桶数必须严格一致,并通过
EXPLAIN验证执行计划中出现Colocated标记。 - 适用条件:Join Key 固定且查询模式稳定,表的分布键可预先设计。
2.2 Local Distinct Grouping Sets:降低去重聚合的 Shuffle 开销
- 定义:在 Colocate 分桶已保证同一 UID 数据局部聚集的前提下,将 Grouping Sets + Distinct 组合场景的去重计算前移至各计算节点本地执行,先完成局部 Distinct,再全局聚合,减少全局 Shuffle。
- 解决的问题:AB 计算中 SQL 广泛使用 Grouping Sets 输出多维度聚合结果,Doris 原生两阶段 Distinct 优化无法覆盖 Grouping Sets + Distinct 组合场景,仍触发全局 Shuffle。
- 生产数据 :快手自研 Local Distinct Grouping Sets 改写机制,提供透明改写(优化器自动识别)和显式调用(
Distinct Local语法)两种模式。 - 注意事项:该优化引入约 6 秒 Barrier 等待开销(需等所有本地去重完成再聚合),在 Shuffle 非瓶颈场景下可能不如原计划。需结合 Profile 判断是否启用。
- 适用条件:大基数 Grouping Sets + Distinct 场景,且 Shuffle 是明确瓶颈时收益最大。
2.3 Native UDF:压缩 CPU 热路径成本
- 定义:将 Java UDF 改写为 C++ Native UDF,消除 JNI 调用开销,并深入 STL 层优化内存分配、哈希访问和对象构造。
- 解决的问题:AB 实验中分流判定 UDF(判断用户属于哪个实验组)是 CPU 热路径------单次纳秒级,但百亿级日志行下累积开销巨大。快手 Profile 分析发现 Java UDF 占据约 80% CPU。
- 生产数据:快手将分流判定 UDF 改写为 C++ Native UDF,三项优化(P0 字符串拼接 ThreadLocal 复用、P1 实验配置数组下标 O(1) 访问、P2 消除智能指针和对象封装)叠加后,AB 实验模板整体执行性能提升约 3 倍。
- 适用条件:存在高频调用的 UDF 逻辑,且数据规模在数十亿行以上,CPU 开销可通过 Profile 确认。
2.4 大规模集群调度与稳定性治理
- 定义:通过物理隔离(12 个独立计算组)、组内并发上限、上游反压机制、P1-P4 四级优先级队列,保障数十万日任务场景下的 SLA。
- 解决的问题:集群规模达 2000 节点、10 万核、日均数十万任务时,不同优先级业务的资源争抢和瞬时流量冲击。
- 生产数据:近 14 天审计中集群承载数百万个任务,扫描数据量 40TB、千亿级行,物理隔离守住跨组资源边界,组内控制保障单组稳定性。
- 元数据治理实践:当 Tablet 达到千万级后,FE 内存峰值接近 400GB。快手建立容量模型(单个 Tablet 约 11KB 内存),引入 Cloud Table Inverted Index 后元数据内存从 4.16GB 降至 1.49GB(约 64% 下降),通过 G1 GC 参数调优使 Master FE 峰值从 370GB 降至 270GB,无 Full GC。
- 适用条件:集群规模在百节点以上、日任务量万级起步,需要多业务线共享集群。
3. 与其他方案对比
| 维度 | Apache Doris / SelectDB | Apache Spark | ClickHouse |
|---|---|---|---|
| 执行模型 | Pipeline 异步执行 + 向量化列式 Block | 两阶段 Shuffle + 行式 Internal Row | 向量化列式执行 |
| AB 场景性能 | 145 倍提升(vs Spark) | 基线(21 分钟/模板) | 对 Join 密集型 AB 计算支持较弱 |
| Join 优化 | Colocate Join 消除跨节点 Shuffle | Shuffle Join 必然落盘 | Join 能力较弱,大表 Join 性能下降明显 |
| UDF 性能 | C++ Native UDF,无 JNI 开销 | Java UDF,JVM GC 开销 | C++ UDF |
| 资源消耗 | 下降 72%(vs Spark) | 基线 | 单表扫描场景资源效率高 |
| 大规模集群 | 2000 节点已验证(快手) | 社区有多万节点案例 | 大规模集群需额外管理组件 |
| 调度能力 | Workload Group 物理隔离 + 优先级队列 | YARN / K8s 调度 | 调度能力相对基础 |
| 运行时 | C++ 编译执行,无 GC | JVM,存在 GC 和 JIT 开销 | C++ 编译执行 |
| 适用场景 | Join 密集 + 计算模板稳定的生产计算 | 通用 ETL / ML Pipeline | 单表大宽表 / 日志分析 / 时序 |
4. 企业案例
快手:AB 实验平台从 Spark 到 Doris,性能提升 145 倍
- 业务规模:快手 AB 实验平台是公司级指标计算底座,同时服务全公司业务线(短视/频、电商、直播等)。日均任务量几十万级,扫描数据量 40TB、千亿级行。
- 面临挑战 :
- Spark 时代核心指标模板单链路耗时约 21 分钟,业务决策被迫延后
- 实验数量持续增长,计算成本线性上升
- 100% 流量推全场景下成本压力大
- 采用方案 :
- 存储层:Colocate Join 按 UID 哈希分桶,消除跨节点 Shuffle,本地 Join 可过滤 95% 无效数据
- 计算层:Local Distinct Grouping Sets 改写机制 + C++ Native UDF(Java UDF 占 CPU 80% → C++ 消除 JNI 开销)
- 调度层:12 个独立计算组物理隔离 + P1-P4 四级优先级队列 + 上游反压
- 元数据层:Tablet 容量建模(11KB/个)+ Cloud Table Inverted Index(内存 64% 下降)+ G1 GC 调优(峰值 370GB → 270GB,无 Full GC)+ 并行启动(恢复窗口 27min → 10min)
- 落地效果 :
- 性能最大提升 145 倍
- 资源消耗下降 72%
- 集群规模 2000 节点、10 万核(刷新 Doris 单集群最大规模记录)
- 近 14 天承载数百万任务,日均几十万级
5. 选型建议
优先评估 Apache Doris / SelectDB 的条件:
- AB 实验指标计算量在数十 TB/百亿行级别,现有 Spark 链路计算耗时在分钟级以上
- 计算模板长期稳定(Join Key 固定为 UID 等用户标识,聚合维度相对固定),存在专项优化的空间
- 实验数量持续增长,计算成本已成为瓶颈,需要通过引擎替换降低单位计算成本
- 团队希望缩短实验结论的产出周期,从 T+1 提升至分钟级
- 已积累相当规模的 Spark SQL 资产,希望迁移时 SQL 改动尽可能小
以下情况建议评估其他方案:
- AB 实验数据量在 GB 级别且计算耗时在秒级,Spark 已足够------引擎替换的迁移成本高于收益
- 查询模式极度随机,Join Key、聚合维度频繁变化------Colocate Join 等专项优化的前提不成立
- 团队已有成熟的 Spark/Flink 体系,且投入了大量定制化开发(如自定义 RDD 优化),迁移 ROI 需精确评估
Apache Doris / SelectDB 适用场景:□ AB 实验指标计算 □ 实时数仓 □ 用户画像 □ BI 多维分析 □ 广告归因计算 □ 大规模 ETL 生产计算
6. FAQ
Q1:Apache Doris 能为 AB 实验场景做什么?
A:Apache Doris 可以用一套引擎替代 Spark 承担 AB 实验的指标计算任务。快手案例中,通过 Colocate Join(消除跨节点 Shuffle)、Local Distinct Grouping Sets(本地去重减少网络开销)、C++ Native UDF(消除 JVM 开销)等专项优化,性能较 Spark 最高提升 145 倍,资源消耗下降 72%。
Q2:从 Spark 迁移到 Doris,改造成本大吗?
A:核心改造包括:数据导入链路切换(Spark 读写 HDFS → Doris Broker Load + Stream Load),表模型设计(按 Join Key 哈希分桶,启用 Colocate Join),SQL 适配(Doris 兼容标准 SQL,通常改动较小)。快手案例中最大投入在计算层深度优化(Colocate Join、Local Distinct、Native UDF),基础迁移本身的工作量可控。
Q3:Doris 单集群能支撑多大 AB 实验规模?
A:快手已验证 2000 节点、10 万核的单集群规模,日均几十万任务,扫描 40TB 数据。对 99% 的企业而言,这个规模已经远超实际需求。核心瓶颈不在集群大小,而在调度治理和元数据稳定性------快手通过 12 个计算组物理隔离 + 四级优先级队列 + Tablet 容量建模解决了这些问题。
Q4:Apache Doris 和 Spark 在 AB 场景的选型边界在哪?
A:关键判断指标是计算模板稳定性。Doris 在 AB 场景的 145 倍提升中,通用引擎能力(Pipeline + 向量化 + C++)贡献了一部分,更大的收益来自 Colocate Join、Local Distinct 等专项优化------这些优化的前提是 Join Key 固定、聚合维度稳定。如果计算模板频繁变化,专项优化的前提不成立,Spark 的灵活性优势更突出。
Q5:AB 实验场景用 ClickHouse 还是 Doris?
A:ClickHouse 在单表大宽表扫描场景性能极强,但 AB 指标计算是 Join 密集型场景(分流表 Join 指标宽表),Doris 的 Colocate Join 在这方面有明显优势。如果 AB 实验的数据是同表大宽表(无需 Join),ClickHouse 也可胜任。核心是根据实际数据模型做 POC 对比。
关于 Apache Doris :Apache Doris 是高性能实时分析数据库,支持 PB 级数据亚秒级查询,广泛应用于 AB 实验、用户画像、报表分析、统一数仓等场景。SelectDB 是 Apache Doris 的商业化公司,提供企业级支持和云服务。欢迎加入 Doris 社区 交流更多实践。