Kafka -- 避免重平衡
概念
- Rebalance是让Consumer Group下所有的Consumer实例就如何消费订阅主题的所有分区达成共识的过程
- 在Rebalance过程中,所有Consumer实例共同参与,在协调者组件的帮助下,完成订阅主题分区的分配
- 整个Rebalance过程中,所有Consumer实例都不能消费任何消息,因此对Consumer的TPS影响很大
协调者
- 协调者,即Coordinator,负责为Consumer Group执行Rebalance以及提供位移管理和组成员管理等
- Consumer端应用程序在提交位移时,其实是向Coordinator所在的Broker提交位移
- Consumer应用启动时,也是向Coordinator所在的Broker发送各种请求
- 然后由Coordinator负责执行消费组的注册、成员管理记录等元数据管理操作
- 所有Broker在启动时,都会创建和开启相应的Coordinator组件,所有Broker都有各自的Coordinator组件
- 内部位移主题
__consumer_offsets
记录了为Consumer Group服务的Coordinator在哪一台Broker上 - 为某个Consumer Group确定Coordinator所在的Broker,有两个步骤
- 确定由位移主题的哪个分区来保存该Consumer Group数据
partitionId = Math.abs(groupId.hashCode() % offsetsTopicPartitionCount
- offsetsTopicPartitionCount默认为50
- 找出该分区Leader副本所在的Broker,该Broker即为对应的Coordinator
- 确定由位移主题的哪个分区来保存该Consumer Group数据
弊端
- Rebalance影响Consumer端TPS
- Rebalance很慢
- Rebalance效率不高
- 每次Rebalance,Consumer Group下所有成员都需要参与,而且不考虑局部性原理,_之前的分配方案都不会被保留_
- 为了解决这个问题,社区于0.11.0.0版本推出StickyAssignor,即粘性的分区分配策略
- 粘性指的是每次Rebalance,都尽可能地保留之前的分配方案,尽量实现分区分配的最小改动
- 但该策略存在一些Bug,而且需要升级到0.11.0.0才能使用,实际生产环境中用得不多
- 影响Consumer端TPS + 慢属于无解,因此尽量_减少不必要的Rebalance_
发生时机
- 组成员数量发生变化 – 最常见
- Consumer实例增加:一般是基于增加TPS或者提高伸缩性的需要,属于计划内的操作,不属于不必要的Rebalance
- Consumer实例减少:在某些情况下Consumer实例会被Coordinator错误地认为已停止而被踢出Consumer Group
- 订阅主题数量发生变化
- 一般是运维主动操作,很难避免
- 订阅主题的分区数量发生变化
- 一般是运维主动操作,很难避免
实例减少
Consumer端参数
- 当Consumer Group完成Rebalance后,每个Consumer实例都会定期地向Coordinator发送心跳
- 如果某个Consumer实例不能及时地发送心跳
- Coordinator会认为该Consumer已死,并将其从Consumer Group中移除,开启新一轮的Rebalance
- Consumer端有一个参数
session.timeout.ms
,默认值为10秒- 如果Coordinator在10秒内没有收到Consumer Group下某个Consumer实例的心跳,就会认为该Consumer已死
- Consumer端还有另一个参数
heartbeat.interval.ms
,默认值为3秒- 设置得越小,Consumer实例发送心跳的频率就会越高,会额外消耗带宽资源,但能更快地知道是否开启Rebalance
- Coordinator通过将REBALANCE_NEEDED标志封装进心跳响应中,来通知Consumer实例开启Rebalance
- Consumer端还有另一个参数
max.poll.interval.ms
,默认值为5分钟- 该参数用于控制Consumer实际消费能力对Rebalance的影响,限定了Consumer端两次调用poll方法的最大时间间隔
- Consumer如果在5分钟内无法消费完poll方法返回的消息,就会主动发起离开组的请求,开启新一轮的Rebalance
非必要的Rebalance
- Consumer未及时发送心跳,导致被踢出Consumer Group而引发的Rebalance
- 生产配置:
session.timeout.ms=6000
+heartbeat.interval.ms=2000
session.timeout.ms=6000
:为了让Coordinator能够更快地定位已经挂掉的Consumer
session.timeout.ms > 3 * heartbeat.interval.ms
- 生产配置:
- Consumer消费时间过长,主动发起离开组的请求而引发的Rebalance
- 如果消费逻辑很重(如DB操作),可以将
max.poll.interval.ms
设置得大一点
- 如果消费逻辑很重(如DB操作),可以将
- 关注Consumer端的GC表现,频繁的Full GC会引起非预期的Rebalance
参考资料
All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.