这是我参与11月更文挑战的第20天,活动详情查看:2021最后一次更文挑战
相关:Kafka 中的消费者组
之前介绍了 Kafka 的消费者组和 Rebalance 机制,并且分析出一个结论:尽量避免频繁触发 Rebalance,因为它非常耗时,且 Rebalance 期间,Kafka 消费者组是无法工作的。
这一篇分析一下,什么情况下会发生 Rebalance,以及根据这些情况分析如何避免 Rebalance 频繁发生。
在之前的文章中总结过 Rebalance 被触发的三种情况:
- 消费者组中的实例发生变化
- 订阅的主题发生变化
- 主题的分区发生变化
对于以上的三种情况,后两种都是人为操作的结果。对于人为修改主题以及主题分区,必然是因为有相应的需求,因此,只要是为了满足需求和解决问题,这两个操作是无法避免的,因此,我们重点分析第一种情况,也就是消费者组中的实例发生变化的情况。
如果是消费者组中加入了新的实例,也就是有一个与当前消费者组的 Group ID 的消费者实例启动了,那么它就会自动加入到这个消费者组中。这种情况一般也是认为操作的结果,无论是为了增加系统的吞吐量,或者别的原因,这都不属于我们要规避的情况,因此,没有必要避免此类情况下的 Rebalance。
那么就只剩下了消费者中的实例减少这种情况,先分析这种情况是如何发生的。
在 Rebalance 的过程中,主题分区的分配是由一个叫做协调者的组建帮助完成的,当完成 Rebalance 之后,消费者实例会定时向协调者发送心跳通知,表明自己运行状态正常。如果协调者不能及时收到这个通知,那么对应的实例会被人为不可用,就会被移除出所在的消费者组,此时, Rebalance 就发生了。协调者通知剩余的消费者实例进行 Rebalance 的方式,是在心跳通知的响应中加入 REBALANCE_NEEDED 标志。
在这里,我们可以通过修改参数的方式来优化。这里相关的消费者端常见参数有以下几个:
session.timeout.ms
,代表协调者等待消费者心跳通知的超时时间,默认是 10 秒,也就是如果协调者超过 10 秒没有收到某个实例的心跳通知,就会认为它「死了」。heartbeat.interval.ms
,表示消费者发送心跳通知的时间间隔,值越小,心跳通知的频率越高。max.poll.interval.ms
,消费者实例两次 poll 调用的最大时间间隔,默认 5 秒,意味着消费者实例如果无法在 5 秒内处理完 poll 方法返回的消息并发起下一次 poll,那么,它会自己离开消费者组,导致 Rebalance 发生。
对于心跳通知方面的优化:将心跳间隔时间设置为一个较小的值,会增加带宽的消耗,但是可以更及时地知道是否需要开启 Rebalance;心跳通知的超市时间可以设置为心跳间隔的 3 倍,即在实例被判定为不可用之前,可以发送 3 次心跳通知。比如将这两个参数分别设置为 2 秒和 6 秒。
对于对消息的消费时间过长的问题,就需要根据实际的情况,根据业务逻辑实际需要执行的时常,再加上一点冗余的时间,设置为两次 poll 操作的最大间隔时长。这里还要注意,如果消费消息的过程中,会涉及到数据入库或者外部服务组件的调用,还需要考虑其他服务出现不稳定或者网络抖动导致消费者实例消费信息时间过长的情况。