11+ 当前分析版本是kafka最新版本(版本随时变化,最新分析代码请关注仓库:[ https://github.com/coderbruis/kafka ] ( https://github.com/coderbruis/kafka ) ** <font style =" color :#DF2A3F ;" >source_code_analysis分支</font >** ,底层原理持续更新)
22+ 转载请标明出处
33
4+ # Kafka Rebalance流程图
5+
6+ ![ Kafka EAGER Rebalance] ( https://github.com/coderbruis/JavaSourceCodeLearning/releases/download/images-v1/kafka_EAGER_rebalance.png )
7+
8+ ![ Kafka Cooperative Rebalance] ( https://github.com/coderbruis/JavaSourceCodeLearning/releases/download/images-v1/kafka_COOPERATIVE_rebalance.png )
9+
410# Kafka Rebalance 核心流程
511` KafkaConsumer.poll() ` 是消费者触发 rebalance 的主要入口。
612
@@ -629,20 +635,47 @@ if (protocol == RebalanceProtocol.COOPERATIVE &&
629635
630636# EAGER 和 COOPERATIVE 的差异
631637## EAGER
632- EAGER rebalance 的特点是简单直接。
638+ EAGER核心特点:全量停、全量分、再恢复
639+
640+ ### EAGER Rebalance流程
641+
642+ 第一步:触发 Rebalance
643+ 1 . 成员变化:join / leave / session timeout / max.poll.interval 超时等。
644+ 2 . 订阅或元数据变化:订阅 topic 变化、正则订阅匹配变化、partition 数变化等。
645+
646+ 第二步:Coordinator 进入 Rebalance 状态
647+ 1 . Coordinator 将 group 状态切到 PreparingRebalance(可能不是第一次进入rebalance,所以这里状态已经是PreparingRebalance了,正常第一次是在JoinGroup进入Coordinator里,会将状态变更为PreparingRebalance。)
648+ 2 . 现有成员会通过 heartbeat 或 poll 流程感知需要重新加入 group。
649+ 3 . 新成员或需要重分配的成员准备发送 JoinGroupRequest。
650+
651+ 第三步:EAGER 全员撤销旧 assignment,然后 JoinGroup
652+ 1 . 每个 consumer 在 JoinGroup 前执行 onJoinPrepare。
653+ 2 . EAGER 协议下 revoke 当前持有的所有 partitions。
654+ 3 . 调用 onPartitionsRevoked(allAssignedPartitions)。
655+ 4 . 清空本地 assignment,停止这些 partitions 的消费。全组成员进入消费暂停状态(STW)。
656+ 5 . 向 coordinator 发送 JoinGroupRequest,携带 subscription 和支持的 assignor。
657+
658+ 第四步:JoinGroup 完成成员协商
659+ 1 . Coordinator 收集本轮成员的 JoinGroupRequest。
660+ 2 . 选择 leader consumer。
661+ 3 . 选择 assignment strategy / protocol,leader consumer生成新的assignment。
662+ 4 . 生成新的 generationId,同时将group状态变更为COMPLETING_REBALANCE。
663+ 5 . JoinGroupResponse 返回给成员。
664+ 6 . Leader 会拿到所有成员的 subscription metadata。
665+
666+ 第五步:分配 + SyncGroup
667+ 1 . Leader consumer 执行分配算法,比如 Range / Sticky。
668+ 2 . Leader 通过 SyncGroupRequest 把全组 assignment 发给 coordinator。
669+ 3 . Follower 也发送 SyncGroupRequest,但通常不带 assignment。
670+ 4 . Coordinator 保存本轮 assignment,group状态变更为STABLE。
671+ 5 . Coordinator 通过各自的 SyncGroupResponse 返回每个 consumer 自己的 assignment。
672+
673+ 第六步:恢复消费
674+ 1 . Consumer 收到自己的 assignment。
675+ 2 . 更新本地 assignment。
676+ 3 . 调用 onPartitionsAssigned(newAssignedPartitions)。
677+ 4 . 从对应 offset 开始拉取消息,恢复消费。
633678
634- ``` plain
635- onJoinPrepare:
636- revoke all partitions
637- clear local assignment
638-
639- leader assign:
640- assign all partitions again
641-
642- onJoinComplete:
643- assign new partitions
644- trigger onPartitionsAssigned
645- ```
646679
647680优点:
648681
@@ -655,23 +688,70 @@ onJoinComplete:
655688+ 即使某些 partition 仍然分给同一个 consumer,也会先 revoke 再 assign。
656689
657690## COOPERATIVE
658- COOPERATIVE rebalance 的特点是渐进迁移。
659-
660- ``` plain
661- onJoinPrepare:
662- keep still-owned partitions
663- revoke only obviously invalid partitions
691+ COOPERATIVE rebalance 的特点是渐进迁移,不会撤销所有分区导致全部分区STW。
692+
693+ ### COOPERATIVE Rebalance流程
694+
695+ 第一轮:标记迁移,旧 owner revoke(onwer表示持有parition的consumer)
696+ 1 . 成员变化、订阅变化或元数据变化触发 rebalance。
697+ 2 . consumer 发送 JoinGroup 给 coordinator。
698+ JoinGroup metadata 里包含:
699+ ○ 当前 subscription
700+ ○ 当前本地已分配分区,也就是 ownedPartitions
701+ 3 . coordinator 收集所有成员的 JoinGroup。
702+ coordinator 负责:
703+ ○ 选 leader
704+ ○ 选 assignor/protocol
705+ ○ 把所有成员 subscription metadata 返回给 leader
706+ coordinator收集完所有的JoinGroup请求之后,会进入新的generationId(递增)。
707+ 4 . leader consumer 执行 assignor。
708+ CooperativeStickyAssignor 会:
709+ ○ 先计算目标 assignment
710+ ○ 如果某个分区要从旧 owner 转给新 owner
711+ ○ 但旧 owner 在本轮 JoinGroup 里仍上报该分区为 owned
712+ ○ 那么本轮不会把该分区分给新 owner
713+ ○ 同时旧 owner 的本轮 assignment 不再包含该分区
714+ 5 . leader Consumer 通过 SyncGroup 把全组 assignment 提交给 coordinator。其他consumer也会发送一个空的SyncGroup给coorinator
715+ 6 . coordinator 保存 assignment,并通过 SyncGroupResponse 返回每个 consumer 自己的 assignment。
716+ 7 . consumer 处理 SyncGroupResponse。
717+ 本地计算:
718+ ``` text
719+ owned = 当前本地 assignment
720+ assigned = 本轮收到的 assignment
721+
722+ revoked = owned - assigned
723+ added = assigned - owned
724+ ```
725+
726+ 需要注意,第一轮主要是做撤销,但是也可能直接添加新的分区分配结果。因为如果这一轮有某个分区本来就没有旧onwer(旧的持有这个parition的consumer),这一轮就可以直接分配给新onwer。
727+ 8 . 如果 revoked 非空:
728+ ○ 调用 onPartitionsRevoked(revoked)
729+ ○ 调用 requestRejoin()
730+ ○ 后续把本地 assignment 更新为 assigned
731+ 9 . 如果 added 非空:
732+ ○ 调用 onPartitionsAssigned(added)
733+ 注意:正在从旧 owner 转移给新 owner 的分区,第一轮不会出现在新 owner 的 added 里。
734+ 第二轮:旧owner撤销分区,新owner获得第一轮撤销的分区
735+ 1 . 因为第一轮有 consumer 调用了 requestRejoin(),group 再次 rebalance。
736+ 2 . consumer 再次发送 JoinGroup。
737+ 此时旧 owner 的本地 assignment 已经更新,所以它上报的 ownedPartitions 不再包含刚刚 revoked 的分区。
738+ 被撤销的分区不会通过JoinGroup发送给Coordinator,revokeList和addLIst都是通过集合计算来得出的。
739+ coordinator收集完所有的JoinGroup请求之后,会进入新的generationId(递增)。
740+ 3 . coordinator 再次收集成员,选 leader,选协议。
741+ 然后将所有成员 subscription metadata 返回给 leader consumer。
742+ 4 . leader 再次执行 assignor。
743+ 这次 assignor 发现:
744+ ○ 该分区已经没有旧 owner 上报 owned
745+ ○ 可以安全分配给新 owner
746+ 5 . leader 通过 SyncGroup 提交新的全组 assignment。
747+ 6 . coordinator 通过 SyncGroupResponse 返回各成员自己的 assignment。
748+ 7 . 新 owner 处理 assignment。
749+ 本地计算:
750+ added = assigned - owned
751+ 8 . 新 owner 对新增分区调用:
752+ onPartitionsAssigned(added)
664753
665- leader assign:
666- do not immediately reassign partitions still owned by others
667754
668- onJoinComplete:
669- revoke partitions that need migration
670- request another rejoin if needed
671-
672- next rebalance:
673- assign released partitions to new owners
674- ```
675755
676756优点:
677757
0 commit comments