目录
调优
调优是为了满足系统常见的非功能性需求。在众多的非功能性需求中,性能绝对是我们最关心的那一个。不同的系统对性能有不同的诉求,比如对于数据库用户而言,性能意味着请求的响应时间,用户总是希望查询或更新请求能够被更快地处理完并返回。
对 Kafka 而言,性能一般是指吞吐量和延时。
吞吐量,也就是 TPS,是指 Broker 端进程或 Client 端应用程序每秒能处理的字节数或消息数,这个值自然是越大越好。
应用层
producer与consumer
不要频繁地创建 Producer 和 Consumer 对象实例。构造这些对象的开销很大,尽量复用它们。
用完及时关闭这些对象底层会创建很多物理资源,如 Socket 连接、ByteBuffer 缓冲区等。不及时关闭的话,势必造成资源泄露。
利用多线程来改善性能Producer 是线程安全的,你可以放心地在多个线程中共享同一个实例;而 Java Consumer 虽不是线程安全的
broker
尽力保持客户端版本和 Broker 端版本一致
jvm
堆大小
broker大小可以设置为6-8g
精确调整得话,可以根据gc log. 关注full gc后堆空上存活对象的总大小,然后将堆大小设置为该值的1.5~2倍.
手动执行full gc:jmap -histo:live <pid> 就能人为触发 Full GC
gc器的选择
使用 G1 收集器,主要原因是方便省事,至少比 CMS 收集器的优化难度小得多.
一定要尽力避免 Full GC 的出现。其实,不论使用哪种收集器,都要竭力避免 Full GC。
频繁full-gc
在 G1 中,Full GC 是单线程运行的,它真的非常慢。如果你的 Kafka 环境中经常出现 Full GC,你可以配置 JVM 参数 -XX:+PrintAdaptiveSizePolicy,来探查一下到底是谁导致的 Full GC。
g1的大对象
使用 G1 还很容易碰到的一个问题,就是大对象(Large Object),反映在 GC 上的错误,就是“too many humongous allocations”。所谓的大对象,一般是指至少占用半个区域(Region)大小的对象。举个例子,如果你的区域尺寸是 2MB,那么超过 1MB 大小的对象就被视为是大对象。要解决这个问题,除了增加堆大小之外,你还可以适当地增加区域大小,设置方法是增加 JVM 启动参数 -XX:+G1HeapRegionSize=N。默认情况下,如果一个对象超过了 N/2,就会被视为大对象,从而直接被分配在大对象区。如果你的 Kafka 环境中的消息体都特别大,就很容易出现这种大对象分配的问题。
系统
禁掉atime更新
在挂载(Mount)文件系统时禁掉 atime 更新。atime 的全称是 access time,记录的是文件最后被访问的时间。记录 atime 需要操作系统访问 inode 资源,而禁掉 atime 可以避免 inode 访问时间的写入操作,减少文件系统的写操作数。你可以执行 mount -o noatime 命令进行设置。
文件系统得选择
至少选择 ext4 或 XFS。尤其是 XFS 文件系统,它具有高性能、高伸缩性等特点,特别适用于生产服务器。值得一提的是,在去年 10 月份的 Kafka 旧金山峰会上,有人分享了 ZFS 搭配 Kafka 的案例,该报告宣称 ZFS 多级缓存的机制能够帮助 Kafka 改善 I/O 性能,据说取得了不错的效果。
swap空间设置
将 swappiness 设置成一个很小的值,比如 1~10 之间,以防止 Linux 的 OOM Killer 开启随意杀掉进程。你可以执行 sudo sysctl vm.swappiness=N 来临时设置该值,如果要永久生效,可以修改 /etc/sysctl.conf 文件,增加 vm.swappiness=N,然后重启机器即可。
文件连接数
ulimit -n 和 vm.max_map_count。前者如果设置得太小,你会碰到 Too Many File Open 这类的错误,而后者的值如果太小,在一个主题数超多的 Broker 机器上,你会碰到 OutOfMemoryError:Map failed 的严重错误,因此,我建议在生产环境中适当调大此值,比如将其设置为 655360。具体设置方法是修改 /etc/sysctl.conf 文件,增加 vm.max_map_count=655360,保存之后,执行 sysctl -p 命令使它生效。
操作系统页缓存
kafka预留得页缓存越大越好,最小值至少要容纳一个日志段的大小,也就是 Broker 端参数 log.segment.bytes 的值。
该参数的默认值是 1GB。预留出一个日志段大小,至少能保证 Kafka 可以将整个日志段全部放入页缓存,这样,消费者程序在消费时能直接命中页缓存,从而避免昂贵的物理磁盘 I/O 操作。
性能指标调优
吞吐量
参数列表 | 备注 | |
---|---|---|
broker | 增加num.replica.fetchers,不用超过cpu数 | Broker 端参数 num.replica.fetchers 表示的是 Follower 副本用多少个线程来拉取消息,默认使用 1 个线程。如果你的 Broker 端 CPU 资源很充足,不妨适当调大该参数值,加快 Follower 副本的同步速度。因为在实际生产环境中,配置了 acks=all 的 Producer 程序吞吐量被拖累的首要因素,就是副本同步性能。 |
broker | 调优gc,避免full gc | |
producer | batch.size,从默认的16kb增加 512或者 1mb | 默认值比较小16kb,最好加上压缩算法lz4和zstd |
producer | linger.ms, 10~100 | |
producer | compression.type=lz4或zstd | |
producer | 设置 acks=0 或 1 ,不建议 | |
producer | retries=0 | |
producer | 若多线程公用producer,增加buffer.memory | 在多个线程中共享一个 Producer 实例,就可能会碰到缓冲区不够用的情形。倘若频繁地遭遇 TimeoutException:Failed to allocate memory within the configured max blocking time 这样的异常,那么你就必须显式地增加 buffer.memory 参数值,确保缓冲区总是有空间可以申请的。 |
consumer | 多线程或者多进程消费 | |
consumer | 增加fetch.min.bytes参数值 | 可以增加 fetch.min.bytes 参数值。默认是 1 字节,表示只要 Kafka Broker 端积攒了 1 字节的数据,就可以返回给 Consumer 端,适当增加值 |
延时调优
参数列表 | 备注 | |
---|---|---|
broker | num.replica.fetchers | 增加num.replica.fetchers 值以加快 Follower 副本的拉取速度,减少整个消息处理的延时。 |
producer | linger.ms=0 | 希望消息尽快地被发送出去,因此不要有过多停留,所以必须设置 linger.ms=0 |
producer | 不启用压缩,compresssion.type=0 | 压缩操作本身要消耗 CPU 时间,会增加消息发送的延时 |
producer | 设置acks=1 | |
consumer | fetch.min.bytes=1 | 在 Consumer 端,我们保持 fetch.min.bytes=1 即可,也就是说,只要 Broker 端有能返回的数据,立即令其返回给 Consumer,缩短 Consumer 消费延时。 |