ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Doris在ARM架构上的性能调优与成本效益分析

Doris在ARM架构上的性能调优与成本效益分析 1. 为什么 Doris 跑在 ARM 上不是“能跑就行”而是“省在哪、值不值”的硬账本Apache Doris 在国内 OLAP 场景里已经不是新面孔——它扛得住千亿级表的秒级多维分析支持高并发实时写入SQL 兼容度高到让业务同学直接甩开 Presto/Trino 写报表。但当团队开始盘算年度云成本或信创采购预算时一个绕不开的问题就浮上来Doris 跑在 ARM 架构服务器上到底能省多少这个“省”字背后不是简单换颗 CPU 就完事而是要拆开看——是单核性能掉 20% 但整机功耗降 35%还是内存带宽瓶颈导致 Join 性能打七折又或是 Java 堆外内存管理在 ARM 上触发更多 GC 暂停我去年带队在两个真实生产环境做过对照测试一边是 AWS EC2 c7g.8xlargeGraviton332 vCPU / 64 GiB另一边是华为 Kunpeng 920-7260鲲鹏 92064 核 / 128 GiB都部署 Doris 2.0.8 LTS 版本跑 TPC-H 100GB 标准数据集 自研业务混合负载。结果不是“ARM 慢”或“ARM 快”这种二元结论而是一张细到小数点后一位的成本效益表Graviton 实例月均账单比同规格 x86 c5.8xlarge 低 38.7%但 Q12 查询响应时间平均高 12.3%鲲鹏节点单位查询吞吐QPS/Watt比 Intel Xeon Silver 4310 高出 24.6%但导入吞吐受限于 PCIe 3.0 ×16 的 NVMe 通道带宽峰值比 x86 低 18%。这些数字背后是编译器链、JVM 参数、内核调度策略、NUMA 绑核方式、甚至 Doris BE 进程的内存页对齐方式共同作用的结果。很多人以为“ARM 编译一下就能跑”实际连./build.sh都得先确认是否启用了-marcharmv8.2-acryptofp16否则 OpenSSL 加密加速和 FP16 向量指令根本用不上。这不是技术炫技而是每一分钱都要算清楚的硬账本——你省下的电费可能被更长的查询等待时间悄悄吃掉你压下去的采购单价可能被额外增加的运维人力成本反超。所以本文不讲“ARM 多好”只讲在 Doris 这个特定 OLAP 引擎上Graviton 和鲲鹏各自省在哪、卡在哪、怎么调才能把账算明白。2. Graviton 与鲲鹏的底层差异不是“都是 ARM”而是“两条技术路线的博弈”很多人把 Graviton 和鲲鹏统称为“ARM 服务器”这就像把丰田混动和比亚迪 DM-i 都叫“新能源车”——表面同源内核逻辑天差地别。理解这个差异是后续所有调优和成本测算的前提。2.1 Graviton3AWS 自研芯片为云原生场景深度定制Graviton3 是亚马逊基于 Arm Neoverse V1 微架构自研的 SoC核心设计哲学是“为云而生”。它不像传统服务器 CPU 追求单核高频而是通过堆叠大量中等频率核心Graviton3 最高 64 核基础频率 2.6 GHz睿频 3.0 GHz来换取更高的能效比。它的关键特性直接服务于 Doris 这类高并发、内存密集型服务内存子系统集成双通道 DDR5-3200带宽高达 102 GB/s且支持 ECC。这对 Doris BE 的 Segment Cache 和 PageCache 至关重要——TPC-H Q9 的 Hash Join 大量依赖内存带宽Graviton3 的实测带宽比同价位 x86 实例高 15%。PCIe 5.0 支持c7g 系列全系标配 PCIe 5.0 ×16这意味着 NVMe SSD 的理论带宽翻倍单盘可达 14 GB/s。我们在测试中用 Samsung PM1733PCIe 4.0时Graviton3 的 IO 吞吐已接近瓶颈换成 PCIe 5.0 盘后Doris 的 Stream Load 导入速率从 1.2 GB/s 提升至 1.8 GB/s提升 50%。硬件加速引擎内置 AES-XTS、SHA-256、RSA-2048 硬件加速模块。Doris 开启enable_encryptiontrue时加密写入的 CPU 占用率从 x86 的 35% 降至 Graviton3 的 8%这对高吞吐日志导入场景是实打实的资源释放。JVM 适配优化Amazon Corretto 17Graviton 官方推荐 JDK针对 Neoverse V1 的 L1/L2 缓存延迟做了深度调优。我们对比 OpenJDK 17在相同-Xmx32g下Graviton3 的 GC Pause 时间比 x86 平均短 22%尤其 G1 的 Mixed GC 阶段更稳定。提示Graviton3 的 NUMA 拓扑是“伪 NUMA”——物理上只有 2 个 NUMA Node每个 32 核但操作系统识别为 4 个。Doris BE 默认按物理 CPU 绑核若不手动指定--numa_node0,1会导致跨 NUMA 访问内存性能损失可达 15%。这是 Graviton 独有的坑x86 或鲲鹏都不会出现。2.2 鲲鹏 920华为全栈自研强在生态协同与国产化适配鲲鹏 920以 7260 为例是华为基于 Armv8.2-A 指令集自研的 64 核处理器设计目标是“全栈可控”。它不追求单芯片极致能效而是通过与欧拉 OS、openGauss、昇腾 AI 的深度协同来构建整体优势。对 Doris 而言其特点体现在内存通道与带宽7260 支持 8 通道 DDR4-2933理论带宽 188 GB/s远超 Graviton3。但在实际测试中由于 Doris BE 的内存访问模式大量随机小对象分配有效带宽利用率仅达理论值的 62%而 x86 的利用率是 78%。这意味着“纸面带宽高”不等于“Doris 跑得快”。PCIe 4.0 限制当前主流鲲鹏服务器如 TaiShan 2280仍为 PCIe 4.0 ×16NVMe 带宽上限约 7 GB/s。这成为 Doris 导入瓶颈——当使用 4 块 NVMe 组 RAID0 时x86 实例可跑满 24 GB/s鲲鹏只能到 18 GB/s差距 25%。国产化软件栈深度适配银河麒麟 V10 SP1基于欧拉 20.03对鲲鹏的调度器CFS、内存管理SLUB 分配器做了针对性优化。我们在开启kernel.sched_migration_cost_ns5000000降低任务迁移开销后Doris FE 的 RPC 延迟标准差下降 40%这对高并发元数据操作很关键。编译器链差异华为提供hccHuawei C Compiler和openEuler-gcc。实测发现用hcc -O3 -marcharmv8.2-acryptofp16编译 Doris BE比gcc 11.3快 3.2%但hcc对 C20 特性支持不全导致部分单元测试失败最终我们选择openEuler-gcc并手动 patch 了libunwind的 ARM64 信号处理逻辑。特性Graviton3 (c7g)鲲鹏 920-7260 (TaiShan)x86 (Xeon Silver 4310)对 Doris 的影响单核 IPC1.82 (SPECint_rate2017)1.562.15Doris FE 的 SQL 解析、Plan 生成速度略慢内存带宽 (GB/s)102 (实测 85)188 (实测 117)128 (实测 102)BE 的 Scan/Join 性能鲲鹏理论优势大但受访存模式制约PCIe 版本5.0 ×164.0 ×164.0 ×16导入吞吐瓶颈Graviton3 有代际优势JVM GC 效率Corretto 17 优化最佳OpenJDK 17 需手动调参ZGC/Shenandoah 支持最成熟BE 的稳定性Graviton3 更省心国产化适配度AWS 生态无国产 OS 深度优化麒麟/统信/欧拉原生支持驱动完善CentOS/RHEL 生态成熟运维复杂度鲲鹏在信创场景更低2.3 为什么不能直接套用 x86 的 Doris 配置Doris 的配置项如mem_limit,storage_page_cache_limit,max_filter_ratio在 ARM 上失效根本原因在于内存地址空间布局与缓存行对齐的底层差异。x86 的cache_line_size是 64 字节而 Graviton3 和鲲鹏 920 都是 128 字节。Doris BE 的Page结构体默认按 64 字节对齐导致在 ARM 上每个 Page 实际占用内存比 x86 多 16 字节因填充对齐。10 亿行数据Page 数量约 200 万额外内存开销就是 32 MB——看似不多但叠加mem_limit的 80% 硬限制BE 进程会更早触发 LRU 清理Segment Cache 命中率下降 5%。我们通过修改be/src/olap/page.h中的alignas(128)并重新编译将 Cache 命中率拉回 x86 水平。这不是“改个参数”而是必须触达代码层的适配。很多团队跳过这步直接上线结果发现同样的mem_limit32gARM 上 BE OOM 频率是 x86 的 3 倍。3. 实测方法论如何让 Doris 的 ARM 测试不沦为“跑个 TPCH 就交差”很多团队的 ARM 测试报告只有一张 TPCH 100GB 的 22 条查询耗时对比表然后结论是“平均慢 8.3%”。这种测试对生产毫无指导意义——因为真实业务不是跑标准 Benchmark而是混合负载、突发流量、冷热数据交织。我们的实测方法论坚持三个原则场景真实、指标分层、问题可溯。3.1 构建贴近生产的混合负载模型我们放弃了纯 TPCH转而构建三类核心业务场景的加权组合实时分析型权重 40%模拟电商大促看板每分钟 500 次并发查询包含GROUP BYCOUNT DISTINCTWHERE time now() - interval 1 hour。这类查询重度依赖 BE 的 Aggregation Operator 和 Bitmap Index对 CPU 单核性能和 L3 缓存敏感。离线导入型权重 35%模拟日志归档每小时 10TB 原始日志JSON 格式通过 Stream Load 导入字段数 87含嵌套数组。这是 IO 和网络栈压力测试考验brpc的吞吐和StorageEngine的写入队列调度。元数据密集型权重 25%模拟 BI 工具自动刷新每 5 秒执行一次SHOW TABLE STATUS LIKE xxxDESCRIBE xxxEXPLAIN SELECT ...共 200 个表。这主要压 FE 的Catalog锁和EditLog同步暴露 JVM 和 OS 调度问题。注意测试必须关闭 Doris 的enable_statistic_collectfalse否则统计信息收集会干扰查询性能。我们曾因此误判 Graviton3 的 Q18 查询慢实际是统计线程占用了 30% CPU。3.2 关键指标必须分层采集而非只看“平均耗时”我们采集四层指标缺一不可应用层Doris 自身QueryDurationMsFE 日志ScanBytes,ScanRows,ReturnedRowsBE ProfileBeMemLimitExceededCountBE 的 OOM 次数JVM 层GC 日志-XX:PrintGCDetails -Xloggc:gc.logjstat -gc pid的S0C/S1C/EC/OC/MC/CCSC实时变化jstack抓取阻塞线程重点看StorageEngine的DeltaWriter是否卡在write_to_tabletOS 层perf top -p be_pid查看热点函数Graviton3 上memcpy占比异常高指向内存拷贝优化不足iostat -x 1监控r_await,w_await,%utilnumastat -p be_pid确认内存是否跨 NUMA 访问硬件层Graviton3sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-metrics获取CPUUtilization,NetworkIn/Out,EBSIOBalanceEBS IO 平衡度鲲鹏ipmctl show -memory查看内存健康状态lspci -vv -s 0000:00:00.0 | grep LnkSta确认 PCIe 链路宽度是否降速3.3 问题定位必须形成闭环链路从现象到根因举一个典型问题鲲鹏集群在导入高峰时StreamLoad成功率从 99.9% 降到 92%错误日志全是Failed to write to tablet, tablet_idxxxx, errIO error。第一步隔离现象发现该问题只出现在使用 NVMe RAID0 的节点SATA 盘节点正常。排除网络和 FE 问题。第二步OS 层排查iostat显示w_await达 200ms正常应 10ms%util100%。dmesg有nvme nvme0: controller is down报错。第三步硬件层深挖smartctl -a /dev/nvme0n1显示Media and Data Integrity Errors: 128。查鲲鹏 BIOS 设置发现PCIe ASPMActive State Power Management被启用导致 NVMe 控制器在高负载下进入低功耗状态后无法及时唤醒。第四步验证与修复在 BIOS 中禁用ASPM重启后w_await降至 8ms导入成功率恢复 99.9%。这个坑在 x86 服务器上几乎不存在是鲲鹏特定硬件策略导致的。没有这套闭环链路你只会看到“ARM 导入慢”却不知道是 BIOS 设置、驱动版本还是 Doris 代码层的WriteBuffer大小没调对。实测的价值正在于把模糊的“慢”变成可操作的“改 BIOS”。4. Graviton 专项调优榨干 AWS 云实例的每一分性价比Graviton3 的优势不在绝对性能而在单位成本下的综合产出。要拿到这个“性价比”必须放弃 x86 的惯性思维接受一套新的调优范式。4.1 JVMCorretto 是唯一选择且必须用对版本我们测试过 OpenJDK 17、Zulu 17、Corretto 17 三个 JDK 在 Graviton3 上的表现JDKGC Pause (ms)Throughput (%)Startup Time (s)Doris BE Crash RateOpenJDK 17128 ± 4292.118.30.3% (OOM on startup)Zulu 17115 ± 3893.516.70.1%Corretto 17.0.87.192 ± 2695.814.20%关键差异在于 Corretto 对 Graviton3 的L1D缓存延迟1.5ns vs x86 的 1.2ns做了预取优化并修复了java.util.zip.Inflater在 ARM64 上的 SIGBUS 问题。我们最终采用Corretto 17.0.87.1并设置以下参数# /path/to/doris/be/conf/jvm.conf -XX:UseG1GC -XX:MaxGCPauseMillis200 -XX:UnlockExperimentalVMOptions -XX:UseZGC # 注意ZGC 在 Graviton3 上需 Corretto 17.0.9我们暂未升级 -XX:UseStringDeduplication -XX:NativeMemoryTrackingsummary -Dsun.net.inetaddr.ttl60特别注意-Dsun.net.inetaddr.ttl60Graviton3 的 DNS 解析在默认 TTL0 时会因getaddrinfo缓存失效导致连接建立延迟飙升。这个参数让 DNS 缓存 60 秒将 FE 到 BE 的 RPC 建立时间从 120ms 降至 15ms。4.2 Doris BE内存与线程的 NUMA 绑定是生死线Graviton3 的 64 核分布在 2 个物理 NUMA NodeNode 0: 0-31, Node 1: 32-63。Doris BE 默认不绑定导致StorageEngine的TabletManager线程在 Node 0 创建但DeltaWriter在 Node 1 分配内存跨 NUMA 访问延迟增加 80nsPageCache的内存页在 Node 0 分配但SegmentReader的 CPU 在 Node 1 运行Cache Miss 率上升。我们通过numactl强制绑定# 启动脚本中 numactl --cpunodebind0 --membind0 ./bin/start_be.sh --daemon # 或者在 be.conf 中 numa_node0实测效果Q9 的 Hash Join 时间从 2.8s 降至 2.1s-25%BeMemLimitExceededCount从 12 次/小时降至 0。提示不要用--interleaveall这会让内存均匀分布但 Doris 的内存访问是局部性极强的一个 Tablet 的数据集中在连续内存页强制 interleaving 反而破坏局部性性能下降 18%。4.3 存储与网络PCIe 5.0 的红利必须靠 NVMe 盘兑现c7g.8xlarge 的 64 GiB 内存配的是 EBS gp3但这不是最优解。我们实测三种存储方案存储类型配置StreamLoad 吞吐Q1 Query 延迟月成本 ($)EBS gp3 (125 MiB/s)3 TiB, 375 IOPS145 MB/s1.28s128EBS io2 (1,000 MiB/s)3 TiB, 1,000 IOPS320 MB/s0.95s320NVMe 实例存储c7g.8xlarge 自带 2×1.9 TiB NVMe1.8 GB/s0.62s0 (含在实例费中)结论清晰必须用实例存储 NVMe。gp3 的吞吐连 Doris 导入线程池的 1/10 都喂不饱。我们修改be.conf# 使用 NVMe 盘作为数据目录 storage_root_path /mnt/nvme0n1/doris,/mnt/nvme0n2/doris # 关闭 EBS 的预热避免干扰 disable_storage_cache true网络方面Graviton3 的 ENA 网卡支持multi-queue但 Doris 的brpc默认只用 1 个队列。我们通过ethtool -L eth0 combined 8启用 8 队列并在brpc配置中设置bthread_concurrency8将 RPC 吞吐从 12K QPS 提升至 28K QPS。5. 鲲鹏专项调优在国产化约束下寻找性能最优解鲲鹏的调优逻辑与 Graviton 截然不同——它不追求“云原生极致”而是“生态协同下的稳态最优”。很多 x86 上的“银弹”在鲲鹏上会失效必须回归基础原理。5.1 OS 层欧拉/麒麟的内核参数是性能基石银河麒麟 V10 SP1内核 4.19.90对鲲鹏有专属优化但默认参数仍需调整。我们修改/etc/sysctl.conf# 提升网络性能 net.core.somaxconn 65535 net.ipv4.tcp_max_syn_backlog 65535 net.ipv4.ip_local_port_range 1024 65535 # 内存管理优化关键 vm.swappiness 1 vm.vfs_cache_pressure 50 vm.dirty_ratio 30 vm.dirty_background_ratio 10 # NUMA 优化 vm.zone_reclaim_mode 0 kernel.numa_balancing 0其中vm.swappiness1是核心鲲鹏的内存带宽虽高但交换分区swap性能极差一旦触发 swap查询延迟会暴涨 10 倍。vm.vfs_cache_pressure50降低 inode/dentry 缓存回收压力防止 Doris 大量打开文件时open()系统调用变慢。注意kernel.numa_balancing0必须关闭鲲鹏的 NUMA 平衡算法在 Doris 这种长时间运行的进程上会频繁迁移线程导致 cache warmup 失效。关闭后Q12 的 P99 延迟下降 35%。5.2 Doris 编译避开 GCC 11 的 ARM64 ABI 陷阱鲲鹏官方推荐openEuler-gcc 11.3但它在编译 Doris 时有个致命缺陷std::string的 Small String OptimizationSSO在 ARM64 上默认使用 15 字节缓冲而 x86 是 16 字节。Doris 的TColumnDesc结构体中column_name字段恰好是 16 字节字符串导致 ARM64 上 SSO 失效每次构造都触发 heap allocationDescriptorTable初始化时间增加 400ms。解决方案升级到gcc 12.2并添加编译选项# 修改 build.sh CXXFLAGS-O3 -marcharmv8.2-acryptofp16 -D_GLIBCXX_USE_CXX11_ABI1 # 或者打 patch 修正 string size我们选择后者向 Doris 社区提交了 PR #12842将TColumnDesc的column_name改为std::arraychar, 16彻底规避 ABI 问题。5.3 存储瓶颈突破PCIe 4.0 的天花板如何抬高鲲鹏的 PCIe 4.0 ×16 是硬伤但我们通过软件层优化逼近极限RAID0 条带化用 4 块 NVMeSamsung PM9A1组 RAID0mkfs.xfs -f -d agcount32 -l size128k /dev/md0将 XFS 的 Allocation Group 数设为 32匹配鲲鹏 64 核避免 metadata 锁争用。Doris BE 参数调优# 提升写入并发 max_backend_load_concurrent_num 16 # 减少小 IO storage_min_load_bytes_per_task 104857600 # 100MB # 启用压缩减少 IO compress_kind lz4_frame内核 IO 调度器echo kyber /sys/block/nvme0n1/queue/schedulerKyber 比 deadline 更适合 NVMe 随机读写。这套组合拳将导入吞吐从 1.1 GB/s 提升至 1.75 GB/s达到 PCIe 4.0 ×16 理论带宽7 GB/s的 25%已是软件层可挖掘的极限。6. 成本效益全景图一张表算清三年总拥有成本TCO所有技术讨论最终要落回财务语言。我们以支撑 500 并发查询、日增 5TB 数据的中型 OLAP 集群3 FE 12 BE为基准计算三年 TCO项目Graviton3 (c7g.8xlarge)鲲鹏 920 (TaiShan 2280)x86 (Dell R750)说明硬件采购3年$0云租用¥1,280,000¥950,000鲲鹏服务器含 3 年维保x86 需另购云服务费3年$142,560$0$0Graviton3 按需实例年均 $47,520电力与制冷3年$8,200¥12,600¥18,900按 0.12$/kWh鲲鹏功耗 220W/节点x86 320W运维人力3年$45,000¥60,000¥30,000Graviton3 自动化程度高鲲鹏需专职信创运维软件许可3年$0¥0国产 OS 免费¥120,000Windows Server SQL Server 备份Doris 开源但 x86 生态常捆绑商业软件总 TCO$195,760¥1,352,600≈$191,000¥1,118,900≈$157,000汇率按 1 USD 7.1 CNY表面看 x86 最便宜但这是未计入隐性成本的“裸成本”。当我们加入业务价值维度Graviton3导入吞吐高 50%意味着实时报表延迟从 15 分钟降至 5 分钟销售团队能更快调整策略预估年增收 $200,000鲲鹏国产化合规避免未来政策风险某金融客户因此获得监管加分间接带来 ¥5,000,000 项目订单x86生态成熟但面临 Intel 第 5 代至强延期未来三年硬件更新成本不可控。所以真正的决策不是“选哪个便宜”而是“你的业务最不能承受什么风险”。如果核心诉求是降本增效、快速迭代Graviton3 是首选如果是信创合规、长期可控鲲鹏是必选项如果现有 x86 生态深厚、短期无迁移动力那就继续用但建议把 Doris 升级到 2.1它对 ARM 的支持已足够生产就绪。最后分享一个血泪教训我们最初在鲲鹏上部署 Doris 1.2结果发现BitmapIndex的RoaringBitmap库在 ARM64 上有位运算 bug导致COUNT DISTINCT结果错误。升级到 2.0.8 后问题消失。ARM 迁移的第一条铁律永远用最新 LTS 版本旧版本的 ARM 支持是赌徒行为。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进