Kafka Rebalance
什么是Rebalance 为了提升消费效率,kafka会将Topic消息放到多个Partition,消费者Consumer可以以消费组(Consumer Group)的形式进行并行消费 在这个背景下,每个消费者节点负责一个或多个Partition。为了保证负载均衡,多个Partition能均匀分配给消费节点,Kafka需要会根据节点负载进行Rebalance以及维护这个映射 为了提升单个Topic的并发性能,将单个Topic拆分为多个Partition 为了提升横向扩展能力,将多个Partition分布在多个不同的Broker 为了提升可用性,为每个Partition加了多个副本 为了协调和管理kafka集群的数据消息,引入Zookeeper作为协调节点 Reblance过程不是瞬间完成的,而是要经历:注册旧分区👉选举Leader👉分配新分区👉初始化消费者 这一完整过程。在这个期间,所有消费者会停止消费 什么时候会触发Rebalance [最常见] 消费者数量发生变化(服务扩缩容的时候、某个节点出问题了重复重启) 调整了Topic的分区数量(kafka只支持增加),新增的分区需要分配消费者 相同消费组下订阅的Topic列表发生了变化 [隐藏的坑] 消费者心跳超过了配置的session.timeout.ms(通常是45s)没有发,kafka会把这个消费者判定为死亡,从而踢出 [隐藏的坑] 消费超时:通常单批消息超过max.poll.interval.ms(通常是5分钟)没有处理完(没有给ack),kafka会把这个消费者踢出 Rebalance期间会引发哪些问题 上述提到,Reblance过程不是瞬间完成的,且这个期间,所有消费者会停止消费,所以会产生消息积压 所以产生积压的时候,优先看下是否发生了Rebalance 消息重复和丢失(见下方) Rebalance 要靠Coordinator协调,频繁触发会占用Kafka集群的CPU和网络资源 而且Kafka默认的分区分配策略(Range 或 RoundRobin),很容易导致负载不均 比如5个分区分配给2个消费者,可能出现 3个分区 vs 2个分区 的情况,其中一个消费者压力翻倍,处理速度变慢,又会触发新的Rebalance,陷入恶性循环 什么时候会丢消息 通常情况下,Reblance不会直接导致丢消息。消费者的处理和offset提交顺序没处理好,就容易出现丢消息的现象 消费者先提交offset(比如100),然后处理消息 开启了自动提交offset(比如100),也是没处理完就提交offset了 上述两种情况,当消费者在处理过程中断了(宕机、OOM、被kill等),导致Kafka触发Rebalance,其它节点接管这个Partition的消费,会从101开始消费 sequenceDiagram participant A as Consumer A participant K as Kafka Broker participant B as Consumer B Note over A,K: 场景:自动提交 (Auto Commit) A->>K: Poll 消息 (Offset 100-200) activate A Note right of A: 放入本地队列/线程池 Note over A,K: 触发自动提交 (5秒到了) A-->>K: 自动提交 Offset = 200 Note right of K: 记录消费进度 = 200 A->>A: 正在处理 Offset 150... Note right of A: 💥 节点突然宕机 (150-199 未处理完) deactivate A Note over K: 心跳丢失 -> Rebalance K->>B: 分配分区给 B B->>K: 获取已提交 Offset K-->>B: 返回 Offset = 200 B->>K: Poll 下一批消息 (201+) Note right of B: 😱 Offset 150-199 永久丢失 正确的做法应该是先处理消息→再提交 offset,确保消息处理完才更新进度。 ...