前言
对于有状态的应用程序,一个最大的性能瓶颈就是状态shuffle。Kafka consumer存在“Rebalance”概念,这意味着对于给定的M个分区和一个消费者组中的N个消费者,Kafka将尝试平衡消费者之间的负载情况,理想情况下让每个消费者处理M/N个分区。Kafka通过监视消费者的健康状况来动态地调整负载情况,比如:将死去的消费者踢出消费组,将新消费者加入到消费组。当应用程序状态很重时,如果触发多次Rebalance,整个服务可能需要很长时间才能恢复。所以,如何减少不必要的消费者Rebalance次数成为本文的主要内容。

Rebalance触发条件
1.Consumer Group成员变动(如:组内consumer成员数量增加或者减少)。2.订阅的Topics数量变动(如:通过正则表达式订阅)。3.订阅的Partitions数量变动(如:增加分区)
Rebalance现象
Kafka服务端日志、应用程序consumer端日志均可看见相关记录。
Static Membership机制
消费者组成员变动是最频繁的触发Rebalance的条件。如果说想完全避免consumer rebalance,那是不可能的,rebalance的存在并不是没有意义的。我们要做的就是尽量避免不必要的Rebalance,最应该避免的就是错误判断了消费者的退出情况。分布式系统都需要使用心跳机制进行节点状态的管理,心跳频率和心跳超时时间的设置尤为重要,应该尽量避免因为网路抖动造成的误判。Kafka提供两个参数来定义Brokers与Consumers之间的心跳机制,heartbeat.interval.ms定义心跳频率、session.timeout.ms定义心跳超时时间。
而Static Membership机制基于心跳超时时间,引入group.instance.id参数,设置该参数的消费者即为静态成员。静态成员ID是不变的,在心跳超时(session.timeout.ms)之前,该消费者已持有的分区不参与分区Rebalance,直到心跳恢复(consumer重启或者网络异常恢复)或者超时(一直没有心跳)。
那么,使用Static Membership的要求为:
1.消费者consumers端参数必须设置group.instance.id(如: props.put("group.instance.id", "id1");),且同一消费者组内消费者成员必须唯一值。2.消费者consumers端参数必须合理设置:session.timeout.ms。3.Broker端参数必须合理设置:group.min.session.timeout.ms、group.max.session.timeout.ms。4.session.timeout.ms必须位于[group.min.session.timeout.ms、group.max.session.timeout.ms]区间之内。
所谓的合理设置,还是需要根据现场网络环境、负载情况,调试摸索才能确认。
https://cwiki.apache.org/confluence/display/KAFKA/KIP-345%3A+Introduce+static+membership+protocol+to+reduce+consumer+rebalances




