单 AZ · Kafka 4.1.2 · zstd on vs off · 三架构横评

Kafka zstd 压缩基准测试报告

回答四个问题:zstd 的延迟成本吞吐代价两端 CPU 开销落在哪一侧、以及跨 CPU 架构是否有差异。 全部数据来自 ap-northeast-1 真机(r8g Graviton4 / r8a AMD EPYC / r8i Intel,均 .8xlarge、单 AZ、KRaft、RF=3、acks=all), 每 cell 重复 3 次取中位数,执行顺序随机化,含 1 轮预热丢弃。

0 ms
固定速率下 zstd 的 p99 延迟增量(三机型一致)
−40~53%
broker CPU 下降(H1 证实且为负增量)
7.2×
真实业务 JSON 压缩比(合成随机仅 1.26×)
5%
zstd 吞吐跨三架构极差(none 组为 44%)
三条可带走的结论
不饱和运行时,zstd 的延迟成本为零。三机型、两压缩,固定速率下 p50/p95/p99 完全一致。 「压缩会增加延迟」只在接近饱和时成立 —— 那时增加的是排队延迟,不是压缩计算延迟。
压缩 CPU 全部落在 producer,broker CPU 反而下降(−40%~−53%)。 因为 Kafka 是 batch 级压缩:producer 压一次 → broker 原样落盘与复制(不重压)→ consumer 才解压。 字节量砍到 1/7 后,broker 的内核态开销(网络栈/CRC/page cache 拷贝)大幅减少,sys% 降幅是直接证据。
zstd 吞吐存在架构无关瓶颈,加 CPU 无效。三种架构、物理核差一倍,zstd 吞吐全部收敛到同一区间。 要提吞吐应加 producer 实例数或调大 batch/linger,而不是换更强的 CPU。

实验 A · 固定速率延迟(zstd 的延迟成本)

为什么必须固定速率:饱和态下不同压缩跑出不同吞吐,测到的是排队延迟而非服务延迟,横向比较无效。 本实验各组跑同一速率(= min(各组饱和吞吐) × 50%,见 manifest),实测偏差 < 0.02%,此时延迟差才归因于压缩本身。
机型架构物理核固定速率 (msg/s)compressionp50 msp95 msp99 ms样本
r8gGraviton4 (arm64)32233,863none234n=3
r8gGraviton4 (arm64)32233,863zstd234n=3
r8g p99 判定none 全距 4~4 / zstd 4~4无显著差异
r8aAMD EPYC (x86_64)32247,843none234n=3
r8aAMD EPYC (x86_64)32247,843zstd234n=3
r8a p99 判定none 全距 4~4 / zstd 4~4无显著差异
r8iIntel (x86_64)16231,203none356n=3
r8iIntel (x86_64)16231,203zstd356n=3
r8i p99 判定none 全距 6~6 / zstd 6~6无显著差异

实验 B · 饱和吞吐(zstd 的吞吐代价)

本表延迟列已被刻意省略:饱和态各组吞吐不同,其延迟为排队延迟, 脚本已在数据层标记 latency-NOT-comparable-saturated,禁止进入延迟结论。
机型架构物理核none (msg/s)
中位 / 全距
zstd (msg/s)
中位 / 全距
zstd/nonezstd tps/物理核样本
r8gGraviton4 (arm64)32910,022
909,091~912,201
475,992
473,233~476,815
52%14,875n=3
r8aAMD EPYC (x86_64)321,205,364
1,152,572~1,257,862
495,203
490,587~496,802
41%15,475n=3
r8iIntel (x86_64)161,310,187
1,285,967~1,339,360
470,976
470,284~477,897
36%29,436n=3
★ 本次最重要的发现:zstd 存在架构无关瓶颈
none 组跨机型极差 44%(910,022 ~ 1,310,187), 而 zstd 组极差仅 5%(470,976 ~ 495,203)。
三种不同架构、物理核数差一倍(16 vs 32),zstd 吞吐全部收敛到同一区间。 若瓶颈是 CPU 算力,32 核应接近 16 核的两倍 —— 实测是持平。 → 瓶颈在压缩路径的串行段(zstd-jni 的 JNI 边界 / per-batch 压缩不可并行),加核无效
工程含义:想提升 zstd 吞吐,应增加 producer 实例数(更多并行压缩流)或调大 batch/linger 让单次压缩摊薄更多消息,而不是换更强 CPU。

实验 D · 两端 CPU 开销(压缩 CPU 落在哪一侧)

Kafka 是 batch 级压缩:producer 压一次 → broker 原样落盘与复制compression.type=producer 保证不重压)→ consumer 才解压。 所以 CPU 必须在 producer / consumer / broker 三处同时采,缺一不可证伪 H1「broker 压缩 CPU ≈ 0」。 采集口径为 /proc/<pid>/stat 累积计数器差值(不受采样丢峰影响),归一化成「每 GB 的 CPU 秒」使跨速率可比。

真实业务 JSON

字段名/枚举高度重复,熵较低 → 可压。固定速率 230,000 msg/s,两组处理相同条数 → CPU 严格可比。

机型角色none usr/sys %none 合计 %zstd usr/sys %zstd 合计 %Δ 合计CPU 秒/GB (none→zstd)
r8gproducer13.29 / 1.3914.6829.15 / 0.6329.78+103%2.40 → 4.87
r8gconsumer5.46 / 1.687.139.76 / 0.5210.28+44%1.17 → 1.68
r8gbroker4.44 / 6.2910.733.47 / 1.615.09-53% ← H1 证实1.75 → 0.83
r8aproducer9.33 / 1.0110.3527.40 / 0.2127.61+167%1.69 → 4.51
r8aconsumer2.66 / 1.193.855.33 / 0.335.66+47%0.63 → 0.93
r8abroker4.41 / 4.829.234.13 / 1.415.53-40% ← H1 证实1.51 → 0.91
r8iproducer11.73 / 2.4314.1630.81 / 0.9931.80+125%2.31 → 5.20
r8iconsumer0.56 / 0.060.620.39 / 0.070.46-26%0.10 → 0.07
r8ibroker7.67 / 6.2613.935.39 / 2.057.44-47% ← H1 证实2.28 → 1.22

合成随机数据(对照)

可打印字节均匀分布,熵接近上限 → 基本不可压。固定速率 230,000 msg/s,两组处理相同条数 → CPU 严格可比。

机型角色none usr/sys %none 合计 %zstd usr/sys %zstd 合计 %Δ 合计CPU 秒/GB (none→zstd)
r8gproducer12.98 / 1.2614.2459.09 / 1.2460.33+324%2.34 → 9.90
r8gconsumer5.66 / 1.487.1414.52 / 1.3915.90+123%1.17 → 2.61
r8gbroker4.37 / 6.2010.576.68 / 5.3612.03+14%1.73 → 1.97
r8aproducer11.81 / 1.1112.9252.56 / 0.9853.54+314%2.12 → 8.78
r8aconsumer2.72 / 1.213.927.40 / 0.788.18+109%0.64 → 1.34
r8abroker4.53 / 5.309.836.46 / 4.0110.47+7%1.61 → 1.72
r8iproducer12.47 / 1.9214.4057.55 / 1.7459.28+312%2.36 → 9.73
r8iconsumer0.25 / 0.060.3112.49 / 2.0414.53+4587%0.05 → 2.38
r8ibroker7.40 / 6.4413.859.35 / 5.1014.45+4%2.27 → 2.37

实验 C · 压缩比与语料熵(测试数据选错会让结论反转)

方法学要点:压缩比必须用真实业务形态数据测。合成随机数据信息熵接近上限、本就不可压, 用它做选型会得出「zstd 又贵又没用」的错误结论 —— 而这正是本表两组数据的差别所在。
机型语料熵 (bit/Byte)none 磁盘 (GiB)zstd 磁盘 (GiB)压缩比
r8gjson5.11510.931.517.24×
r8gsynth6.56610.908.651.26×
r8ajson5.11514.401.997.23×
r8asynth6.56614.3611.381.26×
r8ijson5.11514.401.997.23×
r8isynth6.56614.3611.391.26×

被排除的数据点

—— 所有 cell 状态均为 OK,无失败、无 rejected、无 CPU 快照异常。

方法学 · 相对既有测试修正的三处硬伤

① 延迟与吞吐必须分开测(最关键)
既有测试用 --throughput -1(拉满)同时得出吞吐与延迟。但饱和态下不同压缩跑出不同吞吐, 此时测到的 avg/p99 主要是队列积压而非服务延迟 —— 吞吐低的那组反而显得延迟更高, 这是队列效应造成的假象,横向比较无效。
本次做法:实验 A 固定速率测延迟(各组同速率,实测偏差 <0.02%);实验 B 拉满只测吞吐, 且其延迟列在数据层被打上 latency-NOT-comparable-saturated 标记,禁止进入延迟结论。
② 补上 CPU 数据,验证「broker 零压缩 CPU」
该论断此前只有机制推理,从未被 CPU 数据证实。本次在 producer / consumer / broker 三处同时采 /proc/<pid>/stat 累积计数器差值(不受采样丢峰影响),并归一化成「每 GB 的 CPU 秒」使跨速率可比。 producer 与 consumer 分机部署,否则两端 CPU 无法拆分归因。
③ 压缩比必须用真实业务形态数据
合成随机数据信息熵接近上限、本就不可压。用它测出的压缩比会严重低估真实收益, 据此选型会得出「zstd 又贵又没用」的错误结论。本次两种语料并列对照并实测各自香农熵。

环境与版本(全部 pin 死)

说明
Region / AZap-northeast-1c单 AZ,消除跨 AZ 网络变量;三机型均在该 AZ 可用(已核实)
拓扑broker×3 + producer×1 + consumer×1两端分机部署 = CPU 归因前提;cluster placement group
机型r8g / r8a / r8i .8xlarge均 32 vCPU / 256 GiB / 15 Gigabit 持续带宽
⚠️ 物理核r8g 32 · r8a 32 · r8i 仅 16 + SMT2DefaultCores 核实。CPU 跨机型比较同时给每 vCPU 与每物理核两口径
为何用 8xlarge4xlarge 是 "Up to 15G" 突发靠网络积分;zstd=off 组字节多会先撞流量整形→ 系统性污染对照组
Kafka4.1.2(KRaft)SHA512 与官方逐字符一致,UserData 内强校验
zstd-jni1.5.6-10,level 3level 由 jshell 直接问库实测,非文档推断
JDKCorretto 21(devel)三机型 JVM flags 逐字符一致(E0-J1 校验通过)
EBS(broker)gp3 1000 GiB / 16000 IOPS / 1000 MB/s确保磁盘不成为瓶颈;若停在 gp3 默认 125 MB/s,off 组会先撞磁盘墙
关键 broker 配置compression.type=producer★ 保证 broker 不重压缩;设成具体算法会解压重压,直接摧毁 H1 的验证前提
topic24 分区 / RF=3 / minISR=2 / acks=allcleanup.policy=delete,避免 compaction 触发意外重压

可复现性声明

全部资产在仓库 zstd-bench/ 下,可一键重跑:
  • cdk/ — CDK v2(TypeScript):单 AZ 5 节点、参数化机型、AMI 走 SSM 动态查、标签隔离 Project=kafka-zstd-bench
  • scripts/05-e0-gate.shE0 环境闸门:16 项校验,任一 blocking 失败即拒绝采数(三机型均 PASS,blocking=0)
  • scripts/10-run-latency-throughput.sh — 实验 A/B(含饱和探测定共同速率、随机化执行顺序、达标率 >2% 偏差即判 rejected)
  • scripts/20-run-cpu-and-ratio.sh — 实验 C/D(含语料生成与熵计算、三端 CPU 采集、NA/负值双重拦截)
  • scripts/60-build-report.py — 本报告生成器(只读 CSV,数字不手改)
  • results/FINAL/ — 全部原始 CSV + manifest(含共同速率推导过程)+ 语料指纹
  • scripts/99-teardown-all.sh — 标签白名单销毁(DRY-RUN 默认,硬排除非本项目资源)

有效性威胁与已采取的对策

威胁对策
饱和态延迟不可比实验 A 固定速率;实验 B 延迟列数据层标记禁用
JIT / page cache 预热每组丢弃 1 轮预热;CPU 采集跳过 45s 预热窗口,只取稳态 120s
时间漂移 / 邻居噪声执行顺序随机化(seed 落 manifest);%steal > 1% 判该 run 无效
网络 / EBS 积分耗尽用持续带宽档 8xlarge;EBS 显式 1000 MB/s;E0 记录上限指纹
broker 意外解压重压compression.type=producer + cleanup.policy=delete + JMX ProduceMessageConversionsPerSec 守卫
消息格式 down-conversionclient 与 broker 同为 4.1.2;E0-X1 校验三节点 jar 校验和一致
GC 线程数伪装成架构差异显式固定 ParallelGCThreads;E0-J1 校验三机型 JVM flags 逐字符一致
CPU 采样得出物理不可能值/proc/stat 取不到时返回 NA(不填 0);负差值判 FAILED_CPU_REGRESSED;producer 多灌 25% 条数确保覆盖采集窗口
把噪声当结论每 cell n=3 报中位数 + 全距;全距重叠即判「无显著差异」
结论适用边界(外部有效性)
本次为 单 AZ、250 B 量级消息、24 分区、单 producer 进程的场景。以下情形结论可能不同: 跨 AZ / 跨云(网络字节量成为瓶颈时,zstd 的吞吐劣势会转为优势)、大消息(≥1 MB)、 多 producer 并发(可能突破本次观测到的 zstd 串行瓶颈)、以及 zstd level ≠ 3 的配置。

数据来源:ap-northeast-1 真机实测,2026-08-04/05。三机型 E0 环境闸门均 PASS(blocking=0)。

本报告由 scripts/60-build-report.pyresults/FINAL/*.csv 自动生成,表格数字未经手工修改。