Kafka 调优
- 调优目标
- 优化漏斗
- 基础性调优
- JVM 层调优
- Broker 调优
- 应用层调优
- 性能指标调优
- 调优吞吐量
- 调优延时
调优目标
Kafka 的性能 :
- 吞吐量 (TPS) : Broker 或 Client 每秒能处理的字节数或消息数 (越大越好)
- 延时 : 从 Producer 发送消息到 Broker 持久化完成的时间间隔 (越短越好) 或 端到端的延时 (End-to-End,E2E ) : 从 Producer 发送消息到 Consumer 成功消费该消息的总时长
优化漏斗
优化漏斗 :
- 应用程序层 : 优化 Kafka 客户端应用程序代码。如 : 用合理的数据结构、缓存计算开销大的运算结果,复用构造成本高的对象。优化效果最为明显,也是较简单的
- 框架层 : 合理设置 Kafka 参数。根据实际场景配置关键参数
- JVM 层 : Kafka Broker 进程是普通的 JVM 进程,对 JVM 的优化
- 操作系统层 : 对操作系统层的优化
基础性调优
挂载 (Mount) 文件系统时 , 禁掉 atime 更新 (access time,文件最后被访问的时间)
- 记录 atime 要操作系统访问 inode 资源
- 禁掉 atime 能避免 inode 访问时间的写入操作,减少文件系统的写操作数
- 命令 :
mount -o noatime
文件系统 : 用 ext4 或 XFS :
- XFS 文件系统 : 具有高性能、高伸缩性等特点,适用生产服务器
- ZFS 多级缓存的机制能改善 I/O 性能
swap 空间 : swappiness=1
,防止 Linux 的 OOM Killer 随意杀掉进程
- 临时设置 :
sudo sysctl vm.swappiness=N
- 永久生效,修改
/etc/sysctl.conf
文件,增加vm.swappiness=N
,重启机器
操作系统层面 :
ulimit -n
:太小,会有 Too Many File Open 错误vm.max_map_count
: 太小,当主题数过多,会有 OutOfMemoryError:Map failed 错误- 生产环境适当调大,修改
/etc/sysctl.conf
文件,增加vm.max_map_count=655360
,执行sysctl -p
生效
操作系统页缓存 :
- Kafka 页缓存越大越好,至少保证一个日志段的大小
log.segment.bytes
(默认 1GB)- Kafka 将日志段全部放入页缓存,能让消费者命中页缓存,避免磁盘 I/O
JVM 层调优
JVM 调优 : 设置堆大小/ GC 收集器的选择
Broker 设置堆大小 : 经验值 : JVM 堆大小 = 6~8GB
- 精确调整 : 关注 Full GC 后,堆上存活对象的总大小,将把堆大小 = 该值的 1.5~2 倍
- 手动 Full GC :
jmap -histo:live
GC 收集器用 G1 收集器
- 避免 Full GC 出现。G1 的 Full GC 是单线程运行,非常慢
- 当 Kafka 出现 Full GC,配置
-XX:+PrintAdaptiveSizePolicy
,查看谁导致 Full GC - 用 G1 问题 : 大对象 (Large Object) (错误 :
too many humongous allocations
) : 至少占半个区域 (Region) 大小的对象 - 例子 : 区域尺寸是 2MB,超过 1MB 对象是大对象
- 解决方法 : 适当增加区域大小,
-XX:+G1HeapRegionSize=N
- 当 Kafka 的消息体特别大时,就容易出现大对象分配问题
Broker 调优
Broker 端调优 : 保持客户端版本和 Broker 端版本一致
- Producer、Consumer、Broker 版本相同,能享受 Zero Copy
- 低版本 Consumer 要与 Producer、Broker 交互,就只能靠 JVM 堆进行中转,走慢速通道
应用层调优
- 不频繁创建 Producer/Consumer : 构造这些对象的开销很大,尽量复用
- 用完就关闭 : 对象会创建很多物理资源,如 : Socket 连接、ByteBuffer 缓冲区。及时关闭,能避免资源泄露
- 利用多线程改善性能 : Java Producer 是线程安全,能在多个线程中共享同一个实例;而 Java Consumer 不是线程安全
性能指标调优
调优吞吐量
生产环境中,用较小的延时,来提升 TPS
- Producer 累积消息时,会将消息发送到内存的缓冲区中,攒够消息数再通过网络 I/O 传输
调优 TPS
参数 | 意义 | |
---|---|---|
Broker | 增加 num.replica.fetchers | Follower 副本用多少个线程来拉取消息 (CPU充足,调大) |
避免 Full GC | Full GC 用 STW 的单线程收集,非常慢 | |
Producer | 增加 batch.size | 增加消息批次大小 |
增加 linger.ms | 增加批次缓存时间 | |
compression.type=lz4 或 **zstd** | 减少网络 I/O ,提升吞吐量 | |
acks = 0 | 坚守同步时间,提升吞吐量 | |
retries = 0 | 不开启重试,提升吞吐量 | |
多线程共享同个Producer , 增加 buffer.memory | 防止 TimeoutException:Failed to allocate memory within the configured max blocking time 异常 | |
Consumer | 多Consumer进程或线程同时消费 | 多线程增加吞吐量 |
fetch.min.bytes=1KB | 让 Broker 一次返回多数据 |
调优延时
调优延时的参数 :
参数列表 | ||
---|---|---|
Broker | 增加 num.replica.fetchers | 增加 Follower 副本的拉取速度,减少整个消息处理的延时 |
Producer | linger.ms = 0 | 消息尽快发送出去,不要过多停留 |
compression.type = none | 压缩操作要消耗 CPU 时间,会增加消息发送的延时 | |
acks = 1 | Follower 副本同步会降低Producer 吞吐量和增加延时 | |
Consumer | fetch.min.bytes = 1 | 只要 Broker 有数据返回,就立刻返回给 Consumer,缩短Consumer 消费延时 |