rebalance概览
consumergroup的rebalance本质上是一组协议,它规定了一个consumergroup是如何达成一致来分配订阅topic的所有分区的。假设某个组下有20consumer实例,该组订阅了有着100个分区的
topic正常情况下,Kafka会为每个consumer平均分配个分区。这个分配过程就被称为rebalance,consumer成功地执行rebalance后,组订阅topic的每个分区只会分配给组内的一个 consumer实例。
新版本consumer使用了Kafka内置的一个全新的组协调协议(group coordinator protocol),对于每个组而言,Kafka的某个broker会被选举为组协调者。
coordinator负责对组的状态进行管理,它的主要职责就是当新成员到达时促成组内所有成员达成新的分区分配方案。
rebalance触发条件
- 组成员发生变更:比如有新的consumer加入组,或者已有的consumer主动离开组,再或者consumer崩溃时则触发rebalance。
- 组订阅topic数发生变更;
- 组订阅topic的分区数发生变更;
rebalance分区分配
默认提供了3中分配策略:range、round-robin、sticky
- range:基于范围思想,将单个topic的所有分区按照顺序排列,然后将这些分区划分成固定大小的分区段,并以此分配给每个xonsumer;
- round-robin:把所有topic的所有分区顺序摆开,然后轮询式地分配给各个consumer;
- sticky:避免上述两种完全无视历史分配方案的缺陷,采用了黏性策略对所有consumer实例进行分配,可以规避极端情况下的数据倾斜 并且在两次rebalance间最大限度地维持了之前的分配方案。
用户根据consumer参数partition.assignment.strategy
来进行设置。
rebalance generation
为了隔离每次rebalance上的数据,新版本consumer设计了rebalance generation用于表示某次rebalance,在consumer中它是一个这个整数 通常从0开始,主要是为了保护consumer group
的,特别是为了防止无效offset提交,比如上一届的consumer成员由于某些原因延迟提交了
offset,但是rebalance之后该group产生了新一届的group成员,而这次延迟的offset提交携带的旧的generation信息,因此这次提交会被consumer group拒绝。
rebalance协议
rebalance本质上是一组协议,group与coordinator共同使用这组协议完成group的rebalance。最新版本Kafka中提供了下面5个协议来处理rebalance相关事宜:
- JoinGroup请求:consumer请求加入组;
- SyncGroup请求:group leader把分配方案同步更新到组内所有成员中;
- Heartbeat请求:consumer定期向coordinator汇报心跳表名自己依然存活;
- LeaveGroup请求:consumer主动通知coordinator该consumer即将离组;
- DescribeGroup请求:查看组的所有信息,包括成员信息、协议信息、分配方案以及订阅信息。
在rebalance过程中,coordinator主要处理consumer发过来的JoinGroup和SyncGroup请求,当consumer主动离组的时候会发送LeaveGroup请求给coordinator;
在成功rebalance之后,组内所有consumer都需要定期向coordinator发送heartbeat请求,二每个consumer也是根据Heartbeat请求的响应中是否包含REBALANCE_IN_PROGRESS
来判断当前group是否开启新一轮rebalance。
rebalance流程
consumer group在执行 rebalance 之前必须首先确定 coordinator 所在的 broker ,并创建与该 broker 相互通信的 Socket 连接 确定 coordinator 的算法与确定 offset
被提交到 consumer offsets 目标分区的算法是相同的:
- 计算__consumer_offsets分区(Math.abs(groupID.hashCode) % offsets. topic.num.partitions);
- 寻找__consumer_offsets分区的leader副本所在的broker,该broker即为这个group的coordinator;
加入和同步更新方案:
- 加入组:组内所有的consumer向coordinator发送JoinGroup请求,当收集全JoinGroup请求后,coordinator选择出 group的leader
consumer,并把所有成员信息以及它们的订阅信息发送给leader consumer。leader consumer负责为整个group 的所有成员制定分配方案。 - 同步更新分配方案:leader开始制定分配方案,即决定每个consumer都负责哪些topic的哪些分区。一旦分配完成,leader会把这个分配方案封装进SyncGroup
请求发送给coordinator。组内每个consumer都会发送,不过只有leader发送的请求中包含分配方案。coordinator接受到分配方案后把属于每个consumer
的方案单独抽取出来作为SyncGroup请求的response返还给各自的consumer。
加入组流程:
同步分配方案流程: