概述

Kafka-producer-pref-testkafka-consumer-pref-test 是对生产者和消费者做性能测试,获取一组最佳的参数值。

压测目的

  1. 根据不同量级的消息处理结果,评估 Kafka 的处理性能是否满足项目需求。
  2. 可以看出哪个地方出现瓶颈,一般有 CPU、内存、网络、磁盘 IO。一般都是网络出现瓶颈。
  3. 在高并发下,网络 IO 或磁盘 IO 成为瓶颈,产生阻塞而导致。

    压测前做的事情

  4. 使用 hdparm 命令测试磁盘读写速度。读在 170MB~200MB/S ,写为 150~170MB/S

  5. 调优 OS。
    1. 页缓存:尽量分配与所有日志的激活日志段大小相同的页缓存大小。
    2. 文件描述符限制:10万以上。修改 /etc/security/limits.conf 文件。
    3. 禁用 swap。
    4. 使用 G1 垃圾回收器。
    5. 分配 6~8GB 堆大小内存。
  6. 基本监控

    1. CPU 负载
    2. 网络带宽
    3. 文件句柄数
    4. 磁盘空间
    5. 磁盘 IO 性能
    6. 垃圾回收
    7. Zookeeper 监控
      1. -Xmx6G
      2. -Xms6G
      3. -XX:MMetaspaceSize=96m
      4. -server
      5. -XX:+UseG1GC
      6. -XX:MaxGCPauseMillis=20
      7. -XX:InitiatingHeapOccupancyPercent=35
      8. -XX:G1HeapRegionSize=16m
      9. -XX:MinMetaspaceFreeRatio=50
      10. -XX:MaxMetaspaceFreeRatio=80

      压测

  7. 压测单分区的吞吐量。


  8. 计算分区数

  9. 创建只有 1 个分区的 topic。

  10. 压测这个 topic 的 producer 吞吐量和 consumer 吞吐量。
  11. 取两者最小值,设为 Tm,而目标吞吐量为 Tt,则分区数量 = Tt / Tm。分区数量一般在 3~10 个。
  12. 注意,当 partition 数量等于 broker 数量时,吞吐量达到最优,后续随着 partition 数量增加,基本稳定。

    计算机器数

  13. 经验公式:2 * ((峰值生产速度 副本数)/100) + 1。

  14. 先拿到峰值生产速度,再根据设定的副本数,就能预估出需要部署的 Kafka 数量。
  15. 比如峰值速度为 40MB/S,生产环境为三副本,则机器数 = 403 / 100 + 1 =

    计算副本数

    副本数量多,可以增强冗余,但是会因为副本同步占用大量带宽,导致网络拥塞。

  16. 我们先取一批旧的历史数据,统计每条消息平均大小。

  17. 然后在此基础上,增加一点就成为 record-size,我们当时统计的是 1.5KB 大小的数据,为了保险起见,设置为 2KB

机器:3 台 816GB 虚拟机,磁盘容量为 6TB 的虚拟机。

测试参数

参数 描述
—topic 指定生产者发送消息的主题
—num-records 测试时发送消息的总记录数
—payload-delimiter 配合 —payload-file 参数使用,
—throughput 每秒发送的最大消息数,-1 表示不限制
—producer-props key1=value1 key2=value2 形式存在,配置相关属性,比如 bootstrap-server 参数就可以写在这里
—print-metrics 在测试结束后打印结果
—transactional-id 配合 transaction-duration-ms 参数使用。如果参数 > 0,则使用。这个参数用于测试并发事务有用
—transaction-duration-ms 事务持续时间。也就是指业务处理时间,当业务处理完成后,才会调用 commitTransaction 提交事务。
—record-size 消息大小
—payload-file 可读的数据文件
  1. [root@localhost bin]# ./kafka-producer-perf-test.sh --throughput -1 --num-records 100000 --topic james --record-size 4096 --producer-props bootstrap.servers92.168.217.130:9092 acks=-1
  2. 29503 records sent, 5900.6 records/sec (23.05 MB/sec), 884.0 ms avg latency, 1771.0 ms max latency.
  3. 30573 records sent, 6114.6 records/sec (23.89 MB/sec), 1000.7 ms avg latency, 1884.0 ms max latency.
  4. 100000 records sent, 7371.369600 records/sec (28.79 MB/sec), 787.85 ms avg latency, 1884.00 ms max latency, 691 ms 50th, 1515 ms 95th, 1835 ms 99th, 1876 ms 99.9th.
  1. ./kafka-producer-perf-test.sh \
  2. --throughput -1 \
  3. --num-records 500 \
  4. --topic james \
  5. --record-size 4096 \
  6. --producer-props bootstrap.servers=192.168.217.128:9092

指定不限制吞吐量(-1),总共 500 记录,每条记录大小 4096 kb。

  1. 500 records sent, 857.632933 records/sec (3.35 MB/sec), 120.67 ms avg latency, 338.00 ms max latency, 111 ms 50th, 232 ms 95th, 253 ms 99th, 338 ms 99.9th.
500 records sent 发送 500 条消息
857.632933 records/sec (3.35 MB/sec) 每秒发送消息记录数
120.67 ms avg latency, 平均延迟时间
338.00 ms max latency 最大延迟时间
111 ms 50th, 232 ms 95th, 253 ms 99th, 338 ms 99.9th. 统计延迟时间占比

如果加上 --print-metrics 可以获得更详细的结果:

  1. Metric Name Value
  2. app-info:commit-id:{client-id=producer-1} : 448719dc99a19793
  3. app-info:start-time-ms:{client-id=producer-1} : 1624188349464
  4. app-info:version:{client-id=producer-1} : 2.7.0
  5. kafka-metrics-count:count:{client-id=producer-1} : 114.000
  6. producer-metrics:batch-size-avg:{client-id=producer-1} : 12351.419
  7. producer-metrics:batch-size-max:{client-id=producer-1} : 12376.000
  8. producer-metrics:batch-split-rate:{client-id=producer-1} : 0.000
  9. producer-metrics:batch-split-total:{client-id=producer-1} : 0.000
  10. producer-metrics:buffer-available-bytes:{client-id=producer-1} : 33554432.000
  11. producer-metrics:buffer-exhausted-rate:{client-id=producer-1} : 0.000
  12. producer-metrics:buffer-exhausted-total:{client-id=producer-1} : 0.000
  13. producer-metrics:buffer-total-bytes:{client-id=producer-1} : 33554432.000
  14. producer-metrics:bufferpool-wait-ratio:{client-id=producer-1} : 0.000
  15. producer-metrics:bufferpool-wait-time-total:{client-id=producer-1} : 0.000
  16. producer-metrics:compression-rate-avg:{client-id=producer-1} : 1.000
  17. producer-metrics:connection-close-rate:{client-id=producer-1} : 0.000
  18. producer-metrics:connection-close-total:{client-id=producer-1} : 0.000
  19. producer-metrics:connection-count:{client-id=producer-1} : 3.000
  20. producer-metrics:connection-creation-rate:{client-id=producer-1} : 0.098
  21. producer-metrics:connection-creation-total:{client-id=producer-1} : 3.000
  22. producer-metrics:failed-authentication-rate:{client-id=producer-1} : 0.000
  23. producer-metrics:failed-authentication-total:{client-id=producer-1} : 0.000
  24. producer-metrics:failed-reauthentication-rate:{client-id=producer-1} : 0.000
  25. producer-metrics:failed-reauthentication-total:{client-id=producer-1} : 0.000
  26. producer-metrics:incoming-byte-rate:{client-id=producer-1} : 349.179
  27. producer-metrics:incoming-byte-total:{client-id=producer-1} : 10592.000
  28. producer-metrics:io-ratio:{client-id=producer-1} : 0.001
  29. producer-metrics:io-time-ns-avg:{client-id=producer-1} : 265282.863
  30. producer-metrics:io-wait-ratio:{client-id=producer-1} : 0.002
  31. producer-metrics:io-wait-time-ns-avg:{client-id=producer-1} : 635654.692
  32. producer-metrics:io-waittime-total:{client-id=producer-1} : 74371599.000
  33. producer-metrics:iotime-total:{client-id=producer-1} : 31038095.000
  34. producer-metrics:metadata-age:{client-id=producer-1} : 0.281
  35. ...

批次大小

序号 batch.size throughput
1 5000 28420.39
2 10000 29985.01
3 20000 29983.21
4 40000
5 60000

数量 100W,控制其它变量不变,得出以下结果:

  • 批次大小到达一定值后,吞吐量会保持不变。这里是 10000
  • 吞吐量到达一定大小时,整个系统的吞吐量达到峰值,后面增大并发,系统吞吐量下降。

    分区数

    image.png
    并不是分区数量越高越好,达到一定值时,吞吐量反而是下降的,一般不要超过机器数量。
    生产者线程数并非越多越好,达到一定数量后,也会趋于稳定。

    性能瓶颈

    可能会影响整体吞吐量的性能瓶颈。

    生产者端

    | 性能瓶颈 | 说明 | | —- | —- | | thread | 测试时的单机线程数 | | batch-size | | | ack | | | message-size | | | compression-code | | | partition | | | replication | | | linger.ms | 两次发送 |

Broker 端

性能瓶颈 说明
num.replica.fetchers 副本抓取的相应参数,如果发生 ISR 频繁进出或 follower 无法追上 leader 的情况,应适当增加该值,默认值 1
num.io.threads Broker 处理磁盘 IO 的线程数,主要进行磁盘 IO 操作,高峰期可能出现 IO 等待。默认值:8
num.network.threads broker 处理消息的最大线程数,主要处理网络 IO,操作 SocketChannel 进行读写。默认值:3,建议调大。

压缩算法

推荐使用 lz4,其它的比如 snappygzip 效果一般。

Broker 端性能瓶颈

  • default.replication.factor
  • num.replica.fetchers
  • auto.create.topics.enable
  • min.insync.replicas
  • unclean.leader.election.enable
  • broker.rack
  • log.flush.interval.messages
  • log.flush.interval.ms
  • unclean.leader.election.enable
  • min.insync.replicas
  • num.recovery.threads.per.data.dir

    规划磁盘容量

  1. 新增消息数量
  2. 消息留存时间
  3. 平均消息大小
  4. 备份数
  5. 是否启用压缩

    带宽

    最大占用带宽资源:70%,超过这个阈值就可能出现丢包。
    常规时间不能使用这么多资源,你必须再额外预留出 2/3 的资源,这是保守的做法,单台服务器使用带宽为 700MB/3 ≈ 340Mbps,那么就可以根据带宽计算满足你目标计算值所需要的机器数量。
因素 考量点 建议
操作系统 Linux 的 Epoll 模型优秀 建议部署在 Linux 上
磁盘 磁盘 IO 性能 普通环境使用机械硬盘,不需要搭建 RAID,分布式系统本来就提供高可用服务
磁盘容量 根据消息数、留存时间预估磁盘容量 实际使用中建议预留 20% ~ 30% 的磁盘空间
带宽 根据实际带宽资源和业务 SLA 预估服务器数量 对于千兆网络,建议每台服务器按 700Mbps 计算,避免大流量下的丢包