Kafka - 参数、性能优化教程(JVM、Replication参数、文件刷盘、日志保留策略)
作者:hangge | 2024-05-27 08:40
一、Kafka 优化
1,JVM 参数调优
(1)默认启动的 Broker 进程只会使用 1G 内存,在实际使用中可能会导致进程频繁 GC,影响 Kafka 集群的性能和稳定性。要判断是否需要调整内存分配的大小,首先通过 jps 命令查看 kafka 进程 id:
![](http://hangge.com/blog_uploads/202402/2024022314190357524.png)
(2)然后通过如下命令根据进程 id 查看 kafka 进程 GC 情况(命令最后的 1000 表示每秒刷新一次):
jstat -gcutil <pid> 1000
(3)运行结果如下,我们主要看 YGC,YGCT,FGC,FGCT 这几个参数:
- YGC:young gc 发生的次数
- YGCT:young gc 消耗的时间
- FGC:full gc 发生的次数
- FGCT:full gc 消耗的时间
![](http://hangge.com/blog_uploads/202402/202402231422507843.png)
(4)如果我们发现 YGC 很频繁,或者 FGC 很频繁,就说明内存分配的少了。此时就需要修改 kafka-server-start.sh 脚本文件:
(5)修改其中的 KAFKA_HEAP_OPTS 参数,比如下面我们给给 kafka 分配了 10G 内存。如果服务器内存充裕,也可以分配 16G。
vi bin/kafka-server-start.sh
(5)修改其中的 KAFKA_HEAP_OPTS 参数,比如下面我们给给 kafka 分配了 10G 内存。如果服务器内存充裕,也可以分配 16G。
export KAFKA_HEAP_OPTS="-Xmx10g -Xms10g -XX:MetaspaceSize=96m -XX:+UseG1GC -XX:MaxGCPauseMillis=20 -XX:InitiatingHeapOccupancyPercent=35 -XX:G1HeapRegionSize=16M -XX:MinMetaspaceFreeRatio=50 -XX:MaxMetaspaceFreeRatio=80"
2,副本连接可靠性参数调优
(1)Replication 相关参数在 server.properties 中配置:
vi config/server.properties
(2)replica.socket.timeout.ms 参数的默认值是 30 秒,它是控制 partiton 副本之间 socket 通信的超时时间,如果设置的太小,有可能会由于网络原因导致造成误判,认为某一个 partition 副本连不上了。我们可以适当将其调大:
replica.socket.timeout.ms=60000
(3)如果一个副本在指定的时间内没有向 leader 节点发送任何请求,或者在指定的时间内没有同步完 leader 中的数据,则 leader 会将这个节点从 Isr 列表中移除。这个时间由 replica.lag.time.max.ms 参数决定,该参数默认为 10 秒。
- 如果网络不好,或者 kafka 压力较大,建议调大该值,否则可能会频繁出现副本丢失,进而导致集群需要频繁复制副本,导致集群压力更大,会陷入一个恶性循环
replica.lag.time.max.ms=50000
3,优化主从同步
(1)从分区和主分区数据同步的过程受到了几个参数的影响:
- num.replica.fetchers:从分区拉取数据的线程数量,默认是 1。我们可以考虑设置成 3,这样可以加快同步速率,但是也会给主分区和网络带宽带来压力。
- replica.fetch.min.bytes:可以通过调大这个参数来避免小批量同步数据,提升吞吐量。
- replica.fetch.max.bytes:这个可以调大,比如说调整到 5m,提升吞吐量。但是不要小于 message.max.byte,也就是不要小于消息的最大长度。
- replica.fetch.wait.max.ms:如果主分区没有数据或者数据不够从分区的最大等待时间,可以考虑同步调大这个值和 replica.fetch.max.bytes,在一批次中同步尽可能多的数据。
![](http://hangge.com/blog_uploads/202403/2024030510282290411.png)
(2)简单来说就是将上面这些参数都调大。尤其是后三个,调大它们的效果,就是为了让从分区一批次同步尽可能多的数据。但也不能一直调大,因为调大到一定地步之后,瓶颈就变成了从分区来不及处理。或者调大到超过了消息的并发量,那么也没意义了。这些参数都是跟机器有关的,所以在实践中我们需要通过不断测试来确认这些参数的最佳值。
4,文件刷盘策略设置
(1)为了减少磁盘写入的次数,broker 会将消息暂时缓存起来(存储在 page cache 中),当消息的个数达到一定阈值或者过了一定的时间间隔后,再 flush 到磁盘,这样可以减少磁盘 IO 调用的次数。这块主要通过两个参数控制:
- log.flush.interval.messages:一个分区的消息数阀值,达到该阈值则将该分区的数据 flush 到磁盘,注意这里是针对分区,因为 topic 是一个逻辑概念,分区是真实存在的,每个分区会在磁盘上产生一个目录
- log.flush.interval.ms:间隔指定时间将内存中缓存的数据 flush 到磁盘中,由文档可知,这个参数的默认值为 null,此时会使用 log.flush.scheduler.interval.ms 参数的值
(2)但是默认的配置下这两个参数值太大,都是 9223372036854775807(long 的最大值)。当遇到断电或机器故障的情况,PageCache 上的数据可能未来得及刷新到磁盘,会造成消息丢失。
(3)因此我们建议修改这两个参数值,首先编辑各 broker 的配置文件:
vi config/server.properties
(4)然后修改这两个参数值:
- log.flush.interval.messages 建议修改成 10000
- log.flush.interval.ms 建议修改成 1000(该单位是毫秒,表示每 1 秒写一次磁盘)
注意:这两个参数需要去掉注释之后才生效。
![](http://hangge.com/blog_uploads/202402/2024022216395447089.png)
5,日志保留策略设置
(1)kafka 中的数据默认会保存 7 天,如果 kafka 每天接收的数据量过大,这样是很占磁盘空间的,我们可以根据实际情况修改数据保存周期。
(2)数据保存周期主要通过如下几个参数控制(同样是修改 server.properties 配置文件):
- log.retention.hours:这个参数默认值为 168,单位是小时,就是 7 天,可以在这调整数据保存的时间,超过这个时间数据会被自动删除
- log.retention.bytes:这个参数表示当分区的文件达到一定大小的时候会删除它,如果设置了按照指定周期删除数据文件,这个参数不设置也可以,这个参数默认是没有开启的
- log.retention.check.interval.ms:这个参数表示检测的间隔时间,单位是毫秒,默认值是 300000,就是 5 分钟,表示每 5 分钟检测一次文件看是否满足删除的时机
6,优化 acks
(1)如果追求性能,而且业务并没有那么严格的消息不丢的要求,我们可以把 acks 设置为 0。
(2)如果追求消息不丢失,那么就应该把 acks 设置为 all,不能把 acks 设置为 0 或者 1。
7,优化批次
(1)优化批次有两个好处,对于生产者本身来说,它发送消息的速率更快;对于 Kafka 来说,同样数量的消息,批次越大,性能越好。
(2)所以当我们的发送者遇到瓶颈之后,就可以尝试调大批次的参数来进一步提高发送性能。和批次有关的有两个参数:
- linger.ms:凑够一个批次的最大等待时间。
- batch.size:一个批次最大能有多少字节。
例如:我之前遇到过一个生产者发送消息的性能问题。后来我们经过排查之后,发现是因为发送性能太差,导致发送缓冲池已经满了,阻塞了发送者。这个时候我们注意到其实发送速率还没有达到 broker 的阈值,也就是说,broker 其实是处理得过来的。在这种情况下,最直接的做法就是加快发送速率,也就是调大 batch.size 参数,从原本的 100 调到了 500,就没有再出现过阻塞发送者的情况了。
(3)调大批次究竟能有多大的优化效果和调整前后批次大小、消息平均大小、borker 负载有关。好的时候 TPS 可以翻倍,差的时候可能也就是提升 10% 不到。所以我们最好亲自动手试一试你的业务调整这个参数性能究竟能提升多少。
![](http://hangge.com/blog_uploads/202403/2024030509161366111.png)
(4)当然,批次也不是说越大越好。因为批次大了的话,生产者这边丢失数据的可能性就比较大。而且批次大小到了一个地步之后,性能瓶颈就变成了 broker 处理不过来了,再调大批次大小是没有用的。最好的策略,还是通过压测来确定合适的批次大小。
(5)发送者被阻塞也可能是因为缓冲池太小,那么只需要调大缓冲池就可以。比如说是因为 topic、分区太多,每一个分区都有一块缓冲池装着批量消息,导致缓冲池空闲缓冲区不足,这一类不是因为发送速率的问题导致的阻塞,就可以通过调大缓冲池来解决。
总之:发送者阻塞要仔细分析,如果是发送速率的问题,那么调大发送缓冲区是治标不治本的。如果发送速率没什么问题,确实就是因为缓冲池太小引起的,就可以调大缓冲池。如果现实中,也比较难区别这两种情况,就可以考虑先调大批次试试,再调整缓冲池。
![](http://hangge.com/blog_uploads/202403/2024030509205079991.png)
8,启用压缩
(1)Kafka 默认是不启用压缩的,所以如果我们希望进一步提高吞吐量就可以考虑启用压缩。
(2)Kafka 支持 gzip、snappy、lz4、zdtd 等多种压缩算法,我们可以通过性能测试来选择提示吞吐量效果最明显的算法。
- 一般来说,压缩比越高,压缩速率越低;压缩比越低,压缩速率越高。所以选择压缩算法就是看自己的业务场景究竟是偏向压缩比还是偏向压缩速率。不过在真实环境下,一切都要以性能测试为准,而不能仅仅依赖于原理分析。
![](http://hangge.com/blog_uploads/202403/202403050927087347.png)
二、操作系统优化
1,优化 swap
(1)在现代操作系统中,基本都支持交换区,也叫做 swap 分区。当操作系统发现可用的物理内存不足的时候,就会把物理内存里的一部分页淘汰出来,放到磁盘上,也就是放到 swap 分区。
提示:我们可以把 swap 分区看作是“虚拟内存”。可以想到,如果触发了这种交换,性能就会显著下降。交换越频繁,下降越快
![](http://hangge.com/blog_uploads/202403/2024030509593585217.png)
(3)为了优化 Kafka 的性能,可以调小 vm.swappiness。比如说调整到 10,这样就可以充分利用内存;也可以调整到 1,这个值在一些 linux 版本上是指进行最少的交换,但是不禁用交换。
为什么不直接禁用 swap 呢?
- 物理内存总是有限的,所以直接禁用的话容易遇到内存不足的问题。我们只是要尽可能优化内存,如果物理内存真的不够,那么使用交换区也比系统不可用好。
2,优化网络读写缓冲区
(1)Kafka 也是一个网络 IO 频繁的应用,所以调整网络有关的读写缓冲区,效果也会更好。对应的参数有 6 个:
- net.core.rmem_default 和 net.core.wmem_default:Socket 默认读写缓冲区大小。可以考虑调整到 128KB。
- net.core.rmem_max 和 net.core.wmem_max:Socket:最大读写缓冲区。可以考虑调整到 2MB。
- net.ipv4.tcp_wmem 和 net.ipv4.tcp_rmem:TCP 读写缓冲区。它们的值由空格分隔的最小值、默认值、最大值组成。可以考虑调整为 4KB、64KB 和 2MB。
(2)这些参数目的都是调大读写缓冲区,上面列举的值只是参考,究竟设置多大,还是要根据 broker 的硬件资源来确定。
3,优化磁盘 IO
Kafka 也是一个磁盘 IO 密集的应用。优化磁盘 IO 的两个方向就是使用 XFS 作为文件系统,并且禁用 atime。
- 使用 XFS 作为文件系统是因为它要比 EXT4 性能更好更加适合 Kafka。在同等情况下,使用 XFS 的 Kafka 要比 EXT4 性能高 5% 左右。
- 禁用 atime 是因为 atime 是指文件最后的访问时间,而本身 Kafka 用不上。
全部评论(0)