KafkaNotes

第 17 章:性能调优:压测、参数与容量规划

zjc 于 2026-01-17 发布

这是《Kafka 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开,代码块保留了原书可直接运行的版本。 调优的第一原则:没有测量就没有调优。本章给出一套从压测定位、分层调参到容量规划的完整方法。

17.1 先建立基线

任何改动前,先回答三个问题:

  1. 当前吞吐是多少(条/秒、MB/秒)?
  2. 端到端延迟是多少(P99)?
  3. 瓶颈在哪:生产者、网络、Broker 磁盘、还是消费者?
Producer -> 网络 -> Broker(磁盘/页缓存/副本) -> 网络 -> Consumer -> 下游

逐段测量,找出最长的那块板,避免“凭感觉调参”。

17.2 官方压测工具

生产者压测

bin/kafka-producer-perf-test.sh \
  --topic perf-test \
  --num-records 1000000 \
  --record-size 1024 \
  --throughput -1 \
  --producer-props bootstrap.servers=localhost:9092 \
      acks=all linger.ms=10 compression.type=zstd

输出关注:records/secMB/secavg latencymax latencypercentile

消费者压测

bin/kafka-consumer-perf-test.sh \
  --bootstrap-server localhost:9092 \
  --topic perf-test \
  --messages 1000000 \
  --reporting-interval 1000

压测建议:

17.3 操作系统层

建议
文件句柄 ulimit -n 100000+,分区多时按 分区数*3 估算
swappiness vm.swappiness=1,尽量避免页缓存被换出
文件系统 XFS(首选)或 ext4,挂载 noatime
磁盘 SSD/NVMe,多盘条带化 log.dirs;避免与 OS、日志混盘
网络 万兆起步,txqueuelen、缓冲区按需调整
时间同步 NTP/chrony,时间戳语义依赖时钟

Kafka 是少数“吃页缓存比吃 JVM 堆更划算”的服务:

机器 64GB 内存:
  Broker JVM 堆 6-8GB(足够)
  剩余 50GB+ 留给页缓存(关键!)

17.4 Broker 调优

参数 默认 建议
num.network.threads 3 NetworkProcessorAvgIdlePercent,低于 30% 加到 6-8
num.io.threads 8 RequestHandlerAvgIdlePercent,磁盘快时适当加大
num.replica.fetchers 1 ISR 频繁收缩/写入大时调到 2-4
num.partitions 1 新 topic 默认分区数,显式规划覆盖
log.flush.interval.messages MAX 保持默认,依赖 OS
socket.send/receive.buffer.bytes 100KB 大流量可调大到 1MB
replica.fetch.max.bytes 1MB 与生产端大消息匹配
message.max.bytes ~1MB 大消息需同步调客户端

核心指标驱动:

NetworkProcessorAvgIdlePercent  < 0.3 -> 加网络线程
RequestHandlerAvgIdlePercent    < 0.3 -> 加 IO 线程
UnderReplicatedPartitions       > 0 持续 -> 副本追赶能力不足
RequestLatencyAvg               高 -> 磁盘/页缓存/请求堆积

17.5 生产者调优

高吞吐模板:

linger.ms=20
batch.size=65536
compression.type=zstd
buffer.memory=67108864
acks=1            # 若业务允许;可靠场景保持 all

低延迟模板:

linger.ms=0
acks=1
compression.type=lz4
enable.idempotence=true

取舍关系:

17.6 消费者调优

fetch.min.bytes=1
fetch.max.wait.ms=500
max.partition.fetch.bytes=2097152
max.poll.records=500

吞吐优先时:

延迟优先时:fetch.min.bytes=1、小 max.poll.records、处理逻辑轻量化。

17.7 JVM 调优

推荐起点:

-Xms6g -Xmx6g
-XX:+UseG1GC
-XX:MaxGCPauseMillis=20
-XX:InitiatingHeapOccupancyPercent=35

要点:

17.8 容量规划

磁盘

日数据量 = 峰值MB/s * 86400 (按均值更准)
保留7天 * 副本3 * 压缩比(约0.7) * 1.2(索引/元数据)

例:均值 100MB/s -> 100*86400=8.64TB/天(单副本)
    保留7天、RF=3 -> 8.64*7*3*1.2 ≈ 217TB

网络

入流量 = 写入
出流量 = 写入 * 消费副本数(消费者数) + 副本同步
例:写入 1Gbps、3个独立消费组、RF=3
    Broker 间副本 ≈ 2x 写入,出向消费 ≈ 3x 写入
    万网卡可能接近打满,需评估

分区与机器

17.9 一个调优案例

现象:生产端 P99 从 50ms 涨到 2s,吞吐只有 3 万条/s。

排查

  1. Broker RequestHandlerAvgIdlePercent=0.9(不忙);
  2. 磁盘 util 95%(写入瓶颈);
  3. 消息未压缩、linger.ms=0,请求碎片化严重。

动作:开启 zstd、linger.ms=15batch.size=64KB;两块新盘加入 log.dirs

结果:磁盘 util 降到 65%,吞吐 12 万条/s,P99 80ms。

这个案例说明:调优常常不是“加线程”,而是减少无效 IO 与请求碎片化

本章小结

思考题

  1. 为什么“给 Kafka 开 32GB 大堆”通常反而会伤害性能?
  2. linger.ms 从 0 调到 20ms,为什么吞吐和延迟可能同时变得更可控?
  3. 规划一个日均 10TB、保留 3 天、RF=3 的集群,需要多少裸容量?