从触发条件到分区分配,完整梳理 Rebalance 的全生命周期、分配策略与最佳实践
新的 Consumer 加入 Group,或已有的 Consumer 异常退出(心跳超时、主动关闭)
Consumer 使用 subscribe() 动态改变订阅的 Topic 列表
Topic 的 Partition 数量增加或减少(如管理员执行了扩分区操作)
Consumer 在 session.timeout.ms 内未发送心跳,Coordinator 将其踢出 Group
单次 poll() 超过 max.poll.interval.ms,被认为"不活跃"
Group Coordinator 所在 Broker 宕机,新 Coordinator 接管后触发 Rebalance
📌 关键点:Rebalance 是 Group 级别 的——一旦某个 Consumer 变动,整个 Consumer Group 内所有 Consumer 都会暂停消费参与 Rebalance!这就是为什么频繁 Rebalance 会严重影响吞吐。
Consumer 根据 __consumer_offsets Topic 的 Partition 分布算法:hash(group_id) % num_partitions
找到负责该 Consumer Group 的 GroupCoordinator 节点(某台 Broker),建立 TCP 连接
// 消费者端配置
group.id = "my-order-group"
// __consumer_offsets 默认 50 个分区
// hash("my-order-group") % 50 → 决定哪个 Broker 是 Coordinator
Group 内所有 Consumer 暂停 poll()!
正在处理的消息可能被中断,这是 Rebalance 对业务最大的影响
每个 Consumer 向 Coordinator 发送 JoinGroup 请求,携带:
• group_id
• member_id
• 协议类型 & 协议列表
• 订阅的 Topic 列表
Coordinator 从所有成员中选举一个 Leader(通常是第一个发送 JoinGroup 的成员),其余为 Follower
Coordinator 向 Leader 发送完整的成员列表 + 可用 Topic/Partition 信息。
Leader 根据分配策略计算分配方案,生成 assignment map
所有 Consumer 发送 SyncGroup 请求。
• Leader:携带完整的分配方案
• Follower:assignment 为空
Coordinator 收集到 Leader 的分配方案后,将各自的 assignment 返回给每个 Consumer
各 Consumer 收到自己被分配到的 Partition 列表,更新本地状态
根据分配结果重置 Offset:
• 新分配的 Partition → 按 auto.offset.reset 策略
• 已有历史的 Partition → 从上次提交位置继续
Consumer 恢复 poll() 循环,开始从新分配的 Partition 拉取消息并处理
Kafka 支持多种分区分配策略,通过 partition.assignment.strategy 配置:
N = ⌊partitions/consumers⌋StickyAssignor 使用效果最好| 策略 | 均匀性 | Rebalance 影响 | 适用场景 | Kafka 版本 |
|---|---|---|---|---|
| Range | ⭐⭐⭐ 单 Topic OK | 大(全局暂停) | 单 Topic、简单场景 | 全版本 |
| RoundRobin | ⭐⭐⭐⭐ 更均匀 | 大(全局暂停) | 多 Topic、需均衡负载 | 全版本 |
| Sticky | ⭐⭐⭐⭐ | 中(减少迁移) | 高可用、减少抖动 | 0.11+ |
| Cooperative | ⭐⭐⭐⭐⭐ | 小(渐进式!) | 生产环境推荐 | 2.4+ |
| 参数 | 默认值 | 作用 | 调优建议 |
|---|---|---|---|
session.timeout.ms |
45s | Consumer 心跳超时阈值 | 适当增大(如 20-30s),避免网络波动误判 |
heartbeat.interval.ms |
3s | 心跳发送间隔 | 设为 session.timeout 的 1/3,即 6-10s |
max.poll.interval.ms |
5min | 两次 poll() 最大间隔 | 如果业务处理慢,必须调大!否则会被踢出 |
max.poll.records |
500 | 每次 poll 最大消息数 | 处理慢时减小此值(如 100-300),缩短单次处理时间 |
partition.assignment.strategy |
Range | 分区分配策略 | 多 Topic 推荐 RoundRobin 或 CooperativeStickyAssignor |
⚠️ 经典坑:你的 Consumer 处理一条消息要 10 秒,max.poll.interval.ms 还是默认 5 分钟。看起来没问题?但如果一次拉了 500 条,500 × 10s = 5000s ≫ 300s,直接超时被踢出!
解决方案:max.poll.records=50 或 max.poll.interval.ms=600000
💡 减少 Rebalance 的黄金法则:
1. 避免在高峰期重启 Consumer / 滚动发布
2. 合理设置超时参数(session.timeout ≥ 3 × heartbeat.interval)
3. 保证 Consumer 心跳线程和处理线程隔离
4. 升级 Kafka ≥ 2.4,使用 CooperativeStickyAssignor 实现渐进式 Rebalance
5. 监控 consumer-lag 和 rebalance 频率,设置告警
找 Coordinator →
全员 JoinGroup →
选 Leader 分配 →
SyncGroup 同步 →
恢复消费
核心痛点:STW(Stop-The-World)—— Rebalance 期间整个 Group 停止工作。解决方案:CooperativeSticky + 参数调优