38 | 调优Kafka,你做到了吗?


管理与监控

38 | 调优Kafka,你做到了吗?

调优目标

通常来说,调优是为了满足系统常见的非功能性需求。在众多的非功能性需求中,性能绝对是最被关心的那一个。

对 Kafka 而言,性能一般是指吞吐量和延时。

吞吐量,也就是 TPS,是指 Broker 端进程或 Client 端应用程序每秒能处理的字节数或消息数,这个值越大越好。

延时,它表示从 Producer 端发送消息到 Broker 端持久化完成之间的时间间隔。这个指标也可以代表端到端的延时(End-to-End,E2E),也就是从 Producer 发送消息到 Consumer 成功消费该消息的总时长。和 TPS 相反,延时越短越好。

总之,高吞吐量、低延时是调优 Kafka 集群的主要目标。

优化漏斗

优化漏斗是一个调优过程中的分层漏斗,可以在每一层上执行相应的优化调整。总体来说,层级越靠上,其调优的效果越明显,整体优化效果是自上而下衰减的,如下图所示:

在这里插入图片描述

第 1 层:应用程序层。 它是指优化 Kafka 客户端应用程序代码。比如,使用合理的数据结构、缓存计算开销大的运算结果,抑或是复用构造成本高的对象实例等。这一层的优化效果最为明显,通常也是比较简单的。

第 2 层:框架层。 它指的是合理设置 Kafka 集群的各种参数。毕竟,直接修改 Kafka 源码进行调优并不容易,但根据实际场景恰当地配置关键参数的值,还是很容易实现的。

第 3 层:JVM 层。 Kafka Broker 进程是普通的 JVM 进程,各种对 JVM 的优化在这里也是适用的。优化这一层的效果虽然比不上前两层,但有时也能带来巨大的改善效果。

第 4 层:操作系统层。 对操作系统层的优化很重要,但效果往往不如想象得那么好。与应用程序层的优化效果相比,它是有很大差距的。

基础性调优

操作系统调优

  1. 在操作系统层面,最好在挂载(Mount)文件系统时禁掉 atime 更新。
    atime 的全称是 access time,记录的是文件最后被访问的时间。记录 atime 需要操作系统访问 inode 资源,而禁掉 atime 可以避免 inode 访问时间的写入操作,减少文件系统的写操作数。可以执行 mount -o noatime 命令进行设置。
  2. 文件系统,建议选择 ext4 或 XFS。
    尤其是 XFS 文件系统,它具有高性能、高伸缩性等特点,特别适用于生产服务器。
  3. swap 空间的设置,建议将 swappiness 设置成一个很小的值,比如 1~10 之间,以防止 Linux 的 OOM Killer 开启随意杀掉进程。
    可以执行 sudo sysctl vm.swappiness=N 来临时设置该值,如果要永久生效,可以修改 /etc/sysctl.conf 文件,增加 vm.swappiness=N,然后重启机器即可。
  4. 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 命令使它生效。
  5. 操作系统页缓存,这对 Kafka 而言至关重要。
    在某种程度上,可以这样说:给 Kafka 预留的页缓存越大越好,最小值至少要容纳一个日志段的大小,也就是 Broker 端参数 log.segment.bytes 的值。该参数的默认值是 1GB。预留出一个日志段大小,至少能保证 Kafka 可以将整个日志段全部放入页缓存,这样,消费者程序在消费时能直接命中页缓存,从而避免昂贵的物理磁盘 I/O 操作。

JVM 层调优

1. 设置堆大小。

将 JVM 堆大小设置成 6~8GB。

2.GC 收集器的选择。

建议使用 G1 收集器,主要原因是方便省事,至少比 CMS 收集器的优化难度小得多。

Broker 端调优

尽力保持客户端版本和 Broker 端版本一致。 如果版本的不一致,它会令 Kafka 丧失很多性能收益,比如 Zero Copy。

在这里插入图片描述

图中蓝色的 Producer、Consumer 和 Broker 的版本是相同的,它们之间的通信可以享受 Zero Copy 的快速通道;相反,一个低版本的 Consumer 程序想要与 Producer、Broker 交互的话,就只能依靠 JVM 堆中转一下,丢掉了快捷通道,就只能走慢速通道了。因此,在优化 Broker 这一层时,只要保持服务器端和客户端版本的一致,就能获得很多性能收益。

应用层调优

不要频繁地创建 Producer 和 Consumer 对象实例。构造这些对象的开销很大,尽量复用它们。

用完及时关闭。这些对象底层会创建很多物理资源,如 Socket 连接、ByteBuffer 缓冲区等。不及时关闭的话,势必造成资源泄露。

合理利用多线程来改善性能。Kafka 的 Java Producer 是线程安全的,可以放心地在多个线程中共享同一个实例;而 Java Consumer 虽不是线程安全的,但也有两套多线程方案,具体查看 20 | 多线程开发消费者实例

性能指标调优

调优吞吐量

以 Kafka Producer 为例。假设它以 2ms 的延时来发送消息,如果每次只是发送一条消息,那么 TPS 自然就是 500 条 / 秒。但如果 Producer 不是每次发送一条消息,而是在发送前等待一段时间,然后统一发送一批消息,比如 Producer 每次发送前先等待 8ms,8ms 之后,Producer 共缓存了 1000 条消息,此时总延时就累加到 10ms(即 2ms + 8ms)了,而 TPS 等于 1000 / 0.01 = 100,000 条 / 秒。由此可见,虽然延时增加了 4 倍,但 TPS 却增加了将近 200 倍。这其实也是批次化(batching)或微批次化(micro-batching)目前会很流行的原因。

在实际环境中,用户似乎总是愿意用较小的延时增加的代价,去换取 TPS 的显著提升。毕竟,从 2ms 到 10ms 的延时增加通常是可以忍受的。事实上,Kafka Producer 就是采取了这样的设计思想。

发送一条消息需要 2ms,那么等待 8ms 就能累积 1000 条消息吗?

可以!Producer 累积消息时,一般仅仅是将消息发送到内存中的缓冲区,而发送消息却需要涉及网络 I/O 传输。内存操作和 I/O 操作的时间量级是不同的,前者通常是几百纳秒级别,而后者则是从毫秒到秒级别不等,因此,Producer 等待 8ms 积攒出的消息数,可能远远多于同等时间内 Producer 能够发送的消息数。

在这里插入图片描述

Broker 端参数num.replica.fetchers 表示的是 Follower 副本用多少个线程来拉取消息,默认使用 1 个线程。如果 Broker 端 CPU 资源很充足,不妨适当调大该参数值,加快 Follower 副本的同步速度。因为在实际生产环境中,配置了 acks=all 的 Producer 程序吞吐量被拖累的首要因素,就是副本同步性能。 增加这个值后,通常可以看到 Producer 端程序的吞吐量增加。

在 Producer 端,如果要改善吞吐量,通常的标配是增加消息批次的大小以及批次缓存时间,即 batch.size 和 linger.ms。

除了以上两个,最好把压缩算法也配置上,以减少网络 I/O 传输量,从而间接提升吞吐量。当前,和 Kafka 适配最好的两个压缩算法是 LZ4 和 zstd。

由于优化目标是吞吐量,最好不要设置 acks=all 以及开启重试。前者引入的副本同步时间通常都是吞吐量的瓶颈,而后者在执行过程中也会拉低 Producer 应用的吞吐量。

如果在多个线程中共享一个 Producer 实例,就可能会碰到缓冲区不够用的情形。倘若频繁地遭遇 TimeoutException:Failed to allocate memory within the configured max blocking time 这样的异常,那么就必须显式地增加 buffer.memory 参数值,确保缓冲区总是有空间可以申请的。

fetch.min.bytes:属性指定了 Consumer 从 Broker 端获取记录的最小字节数。Broker 在收到 Consumer 的数据请求时,如果可用的数据量小于 fetch.min.bytes 指定的大小,那么它会等到有足够的可用数据时才把它返回给消费者。

调优延时

在这里插入图片描述

在 Broker 端,增加 num.replica.fetchers 值以加快 Follower 副本的拉取速度,减少整个消息处理的延时。

在 Producer 端,希望消息尽快地被发送出去,因此不要有过多停留,所以必须设置 linger.ms=0,同时不要启用压缩。因为压缩操作本身要消耗 CPU 时间,会增加消息发送的延时。另外,最好不要设置 acks=all。

在 Consumer 端,保持 fetch.min.bytes=1 即可,也就是说,只要 Broker 端有能返回的数据,立即令其返回给 Consumer,缩短 Consumer 消费延时。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

久违の欢喜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值