这里只讨论"github.com/IBM/sarama"的用法
这里将会从触发重平衡的原因,影响重平衡的因素去介绍重平衡
1. 触发重平衡的原因
-
消费组中新增消费者
因为消费者一旦启动,就会请求broker,所以消费者新增会立即被kakfa识别到,立即触发重平衡(需要和消费者离开的场景区分开)
-
消费者主动离开
例如,对机器缩容的时候,关闭掉了消费者。这里不会立即触发重平衡,因为kafka判断消费者的存活机制是心跳上报,消费者上报有间隔的上报心跳(config.Consumer.Group.Heartbeat.Interval),kafka在一段时间内发现有心跳上报(Consumer.Group.Session.Timeout),就认为消费者仍然存活。
所以当消费者离开后,broker等待一个Session.Timeout时间,发现没有上报,才会触发重平衡 。
所以触发缩容的时候,会可能导致消息大于 Session.Timeout的延迟。
-
消费者无心跳
这里golang的java是client实现略有不同
- java有两种识别方式:
1.认为节点死亡: config.Consumer.Group.Heartbeat.Interval和Consumer.Group.Session.Timeout
2. 认为节点处理速度过慢:max.poll.interval.ms,当消费者会拉取一批数据cache到本地(ChannelBufferSize),一遍执行一遍拉数据,当cache满了,且就会停止拉新数据,直到缓冲区空出新的位置。当某个消费者执行时间过长,导致缓冲区填满且长时间无法空闲出来去容纳新数据,就停止拉数据。当通知拉数据时间>max.poll.interval.ms会认为这个节点处理能力不行,从而触发重平衡,把分配给这个消费者的分区分给其他消费者 - golang:主要依赖于 config.Consumer.Group.Heartbeat.Interval和Consumer.Group.Session.Timeout。然而心跳上报和消费执行时绑定在一起的,互相堵塞,即执行完任务才会上报心跳。所以一旦执行时间大于Session.Timeout,就会导致心跳超时,被踢出消费组
2. 重平衡带来的问题
从触发重平衡的原因上看,重平衡是帮助开发者,实现动态负载均衡,节点异常管理的好方法。但实际使用过程中,因为却带来了大量了的问题。kafka设计之初是为了实现海量数据下的低延迟(毫秒)处理能力,所以默认参数也都是为了做低延迟保障。所以如果对kafka进行优雅调参和正确心跳变得非常重要。
问题:
- 少量任务执行慢,但导致全部分区都重新分配。
- 大量任务处理慢,一直循环重平衡,导致重平衡期间,消费者会处于闲置状态,无法处理任务,任务积压。对已经拿到重平衡后结果的消费者已经执行完的任务时,重平衡变量,导致自己提交失败。
3. 影响重平衡因素
-
- config.Consumer.Group.Heartbeat.Interval和Consumer.Group.Session.Timeout
前面讲到了心跳检测失败,就会触发重平衡,所以根据任务时间调整这两个任务,就能不符合预期的重平衡事件。
Consumer.Group.Session.Timeout>单个消息执行时间
config.Consumer.Group.Heartbeat.Interval如果任务时间较长,配置为一批任务时间的1/3
- config.Consumer.Group.Heartbeat.Interval和Consumer.Group.Session.Timeout
-
- config.ChannelBufferSize 这个参数决定了任务的数量,一批消息的执行时间=单个消息*config.ChannelBufferSize 。如果任务执行很慢,建议参数配置足够小,避免重平衡后导致大量的消息提交失败。
未完待续,写中