前言
Kafka消息积压的问题,核心原因是生产太快
、消费太慢
,处理速度长期
失衡,从而导致消息积压(Lag)的场景,积压到超过队列长度限制,就会出现还未被消费的数据产生丢失的场景。
简单来说,之所以会产生积压,就是消费能力弱
所致。
名词解释
Producer
:消息生产者,就是向 Kafka broker 发消息的客户端;
Consumer
:消息消费者,向 Kafka broker 取消息的客户端;
Consumer Group (CG)
:消费者组,由多个 consumer 组成。消费者组内每个消费者负责消费不同分区的数据,一个分区只能由消费组内一个消费者消费;消费者组之间互不影响。所有的消费者都属于某个消费者组,即消费者组是逻辑上的一个订阅者。
Broker
:一个 Kafka 实例就是一个 broker。一个集群由多个 broker 组成。一个broker可以容纳多个 topic。
Topic
:可以理解为一个队列,生产者和消费者面向的都是一个 topic;
Partition
:为了实现扩展性,一个非常大的 topic 可以分布到多个 broker(即服务器)上,一个 topic 可以分为多个 partition,每个 partition 是一个有序的队列;
Replica
:副本,为保证集群中的某个节点发生故障时,该节点上的 partition 数据不丢失,且 Kafka 仍然能够继续工作,Kafka 提供了副本机制,一个 topic 的每个分区都有若干个副本,一个 leader 和若干个 follower。
leader
:每个分区多个副本的"主",生产者发送数据的对象,以及消费者消费数据的对象都是 leader。
follower
:每个分区多个副本中的"从",实时从 leader 中同步数据,保持和 leader 数据的同步。leader 发生故障时,某个 follower 会成为新的 leader。
如何衡量消息的生产量/消费量/积压量
生产量
:Kafka Topic 在一个时间周期内各partition offset 起止时间差值之和。
消费量
:Kafka Topic 在一个时间周期内某个消费者的消费量。
积压量
:Kafka Topic 的某个Consumer Group残留在消息中间件未被及时消费的消息量
常见案例&应对方法
1. 消费端过载
原因
:消费任务里有消费任务队列满载,消费线程阻塞,导致系统频繁 fullGC 问题
处理方案
:根本解法是提升消费端的能力,增加消费线程数;事前预警,可以增加消费能力监控,以及消息消费积压报警。
2. 消息生产异常导致消费端消费能力不足
原因
:生产者的一些错误导致重复、过多写入任务队列,消息消费能力不足导致该问题。
处理方案
:
1)最根本的处理方案是,代码方面增加健壮性处理,避免此类问题的发生。
2)真的遇到此类问题,需要快速止损,此案例是加速消费积压任务,上线增加消费进程,通过加资源方式修复此类问题。
3)提前预警可以增加队列内消息生产量、消费量等的阈值监控/报警。
3. 消息中间件异常导致消息消费失败
原因
:Kafka broker有一台机器内存故障,导致新代理一台broker不可用,此时业务发布时报获取元数据超时异常
处理方案
:
1)如果公司Kafka等此类公共组件集群发生异常且异常未完全恢复,则不要进行上线等操作
2)当上线服务时发生异常应该立即回滚,而不是为了解决积压消息而全量发布
3)于Kafka组件应该设置开关,如果出现问题可以第一时间关闭相关服务,防止强依赖Kafka导致服务不可用
4)在消费Kafka的业务中不要异步使用自己的线程池,特殊情况会打满线程池
5)上线服务可以将故障Kafka节点从配置中删除,再进行上线重启
4. 消费者业务流程复杂,业务增长后,生产者流量超出消费者能力
原因
:消费者业务流程复杂,生产量达到消费上限后,产生消息积压
处理方案
:
1)对partition扩容增加partition数量
2)将消费者代码修改为多线程并发消费
3)提高单条消息的处理速度,如:优化业务流程,增加缓存,去掉耗时操作
5. 消费者业务流程中存在慢查询
表现
:同时存在MySQL慢查询问题、以及Kafka消息积压的问题,大概率属于慢查询导致的Kafka消息积压。
原因
:消费逻辑中的写MySQL流程存在由于索引不合理导致的慢查询问题
处理方案
:慢查询优化
6. 消费者依赖第三方服务
原因
:回调第三方服务,因第三方接口波动,导致网络慢或者异常,从而影响整体消费端的能力。
处理方案
:
1)做好监控,及时反馈,让依赖的三方接口做优化
2)控制生产者生产速度
3)消费者做好过滤,避免重复处理
7. 消费者组频繁rebalance导致消息积压问题
现象
:
1)消息积压有报警
2)从Kafka manager看,该topic有3个分区,尾数A的ip消费了两个分区,尾数B和C的ip来回变换的消费2号分区,消费进度没有任何变化;从 broker 端日志看,该消费组在频繁的进行rebalance
原因
:
1)max.poll.records = 20,而 max.poll.interval.ms = 1000,也就是说consumer一次最多拉取 20 条消息,两次拉取的最长时间间隔为 1 秒。
也就是说消费者拉取的20条消息必须在1秒内处理完成,紧接着拉取下一批消息。否则,超过1秒后,Kafka broker会认为该消费者处理太缓慢而将他踢出消费组,从而导致消费组rebalance。
根据Kafka机制,消费组rebalance过程中是不会消费消息的,所以看到ip是B和C轮流拉取消息,又轮流被踢出消费组,消费组循环进行rebalance,消费就堆积了
处理方案:消费者客户端减小 max.poll.records 或 增加 max.poll.interval.ms 。RD 将 max.poll.records 设置为 1,重启消费者后消费恢复
补充说明
:
Rebalance 发生的时机有三个:
- 组成员数量发生变化(新加消费者、删除消费者、消费者重启、消费超时等)
- 订阅主题数量发生变化
- 订阅主题的分区数发生变化
consumer客户端相关参数:
-
session.timeout.ms
-
由于broker服务端设置了参数
inigroup.min.session.timeout.ms = 6000 group.max.session.timeout.ms = 300000
- 客户端
session.timeout.ms
的值必须介于两者之间
- 客户端
-
-
heartbeat.interval.ms
- 通常设置值低于 session.timeout.ms 的 1/3
-
max.poll.interval.ms
-
max.poll.records
常见处理方案总结
序号 | 处理方案 |
---|---|
1 | 如果消费者无法提升消费能力,并且消费者数量已达分区数时,消费者增加partition扩容,partition扩容之后无法缩容 |
2 | 消费端增加Consumer消费者 |
3 | 优化单个消费处理流程:慢查询、慢日志优化、简化业务流程 |
4 | 极端情况,消费者无法短时间恢复,并且积压消息可以丢弃时,下线消费者Consumer |
5 | 生产者限流 |
6 | 消费者限流 |
7 | 消费者端,需要慎重使用线程池方式异步消费,避免潜在的fullGC问题 |
8 | 基于业务特点,特别是针对核心场景,对消息生产量、消费量、积压量增加相应的监控、报警规则 |