bigywater.tech
Kafka 内部原理 · 05

Kafka RecordBatch:消息为什么不是一条一条写入

如果 Producer 每条消息都单独发一次网络请求,吞吐量会被请求数量本身卡死。Kafka 客户端会把发往同一个分区的消息攒成一个 RecordBatch 再一起发送。这次对比了"几乎不攒批"和"正常攒批"两种配置,用耗时把差距量化出来。

验证:禁用攒批和正常攒批,同样 2 万条消息耗时差 150 倍
同样是发 2 万条 100 字节的消息、同样是 acks=all、同样是的 3 节点集群,只改了 batch.siz
结论
RecordBatch 存在的意义就是测出来的这 152 倍差距:不攒批的话,Kafka 的吞吐量会被"每条消息一次

验证:禁用攒批和正常攒批,同样 2 万条消息耗时差 150 倍

命令 · java // 配置A:batch.size=1(事实上让每条消息都单独成批,等价于不攒批) producer.send(...) x 20000 // 每条消息都发一次请求 // 配置B:batch.size=65536, linger.ms=20(正常攒批配置) producer.send(...) x 20000 // 消息攒批后打包发送
真实实测 · 本机执行输出
no-batch(batch.size=1) elapsed_ms=11730 for 20000 records
batched(batch.size=65536,linger=20ms) elapsed_ms=77 for 20000 records
speedup=152.3x

同样是发 2 万条 100 字节的消息、同样是 acks=all、同样是的 3 节点集群,只改了 batch.size 和 linger.ms 两个参数:几乎不攒批时耗时 11730ms,正常攒批时只要 77ms,测出 152 倍的速度差。这不是因为网络变快了,而是因为攒批把 2 万次独立的网络往返压缩成了少数几次批量请求——每次请求的固定开销(连接调度、请求排队、Broker 端处理请求头)被分摊到了一批消息上,而不是每条消息都要单独承担一次。

结论

RecordBatch 存在的意义就是测出来的这 152 倍差距:不攒批的话,Kafka 的吞吐量会被"每条消息一次网络请求"这个模式直接限制死,跟消息大小、磁盘速度都没关系,纯粹是请求数量本身的开销。这也是为什么 Kafka 官方不建议为了"降低单条消息延迟"就把 batch.size 调到 1 或者 linger.ms 调到 0——代价可能是上百倍的吞吐损失。

分步演示:攒批把多少次网络请求压缩成了一次

这里用 6 条消息做示意(测量用的是 20000 条,见上一节的耗时数据),机制完全一致,只是把规模缩小到方便逐步回放。

同样6条消息,不攒批要发6次请求,攒批只要1次
刚发生的动作批次被打包发出

    参考与说明

    • 本文的耗时数据来自的 Java KafkaProducer 客户端,两组测试各自使用独立的 topic(batch-demo-nobatch/batch-demo-batched),避免相互干扰;acks=all 保持一致,只改攒批相关参数,保证对比公平。
    • 没有涉及:这次测试是本地回环网络(几乎没有网络延迟),跨机房场景下攒批带来的收益通常会更大(因为单次网络往返的固定成本更高);跨机房数据留给网络延迟相关的文章。
    • 没有涉及:compression.type 对批次大小和网络传输量的影响,这次为了单独隔离"攒批"这一个变量没有开压缩,压缩相关的对比放在另一篇。
    京ICP备2026067502号-1京公网安备11010502063487号