Kafka消息积压、重复、丢失,Rebalance是根源吗?

摘要:大家好,我是小富~ 有次上线监控告警突然炸了,Kafka 订单 Topic 消息积压量突破 10 万条,下游支付服务拿不到数据,部分用户付款后一直显示处理中。 紧急登录集群排查,发现消费者组明明有 3 个节点,却只有 1 个在正常消费,原来
大家好,我是小富~ 有次上线监控告警突然炸了,Kafka 订单 Topic 消息积压量突破 10 万条,下游支付服务拿不到数据,部分用户付款后一直显示处理中。 紧急登录集群排查,发现消费者组明明有 3 个节点,却只有 1 个在正常消费,原来 10 分钟前触发了 Rebalance,另外两个节点还卡在分区重新分配的状态,导致消费能力直接砍半。 所以我的经验是:Kafka出现消息积压、重复、丢失这类问题,直接看是否有Rebalance,能解决大部分问题。 什么时候会触发 Rebalance? Rebalance 本质是消费者组内分区与消费者的重新分配,只有当消费者、分区的对应关系被打破时才会触发,下边咱们看看几种比较常见的场景: 1. 消费者数量变了(最频繁) 扩容触发:业务高峰时加了消费者节点,比如 3 个分区原本 2 个消费者承担,新增 1 个后,需要重新分配成 1 个消费者对应 1 个分区; 下线触发:消费者节点宕机、网络断连,或进程被误杀,比如 3 个消费者少了 1 个,剩下 2 个要接手它的分区,必然触发 Rebalance。 之前我们的日志服务就踩过坑:K8s 节点资源不足,导致消费者 Pod 频繁重启,每重启一次就触发一次 Rebalance,消息积压越来越严重。 2. Topic 分区数加了 Kafka 不支持减少分区,但新增分区时,已存在的消费者组不会自动感知新分区,必须通过 Rebalance,才能把新分区分配给组内消费者。 比如给 order-topic 从 5 个分区扩到 8 个,原本的消费者组只会消费旧的 5 个分区,直到触发 Rebalance 后,才会接手新增的 3 个分区。 3. 订阅的 Topic 变了 消费者组通过 subscribe() 订阅 Topic 时,若修改订阅列表(比如从只订阅 order-topic,改成同时订阅 order-topic 和 pay-topic),会触发 Rebalance,重新分配所有订阅 Topic 的分区。 4. 心跳或消费超时(隐性坑) 消费者靠心跳向 Coordinator(协调者)证明自己活着,这两个超时参数设不好,很容易触发误判式 Rebalance: 心跳超时:消费者每 3 秒(默认 heartbeat.interval.ms)发一次心跳,超过 45 秒(默认 session.timeout.ms)没发,就被判定死亡; 消费超时:处理单批消息超过 5 分钟(默认 max.poll.interval.ms),哪怕心跳正常,也会被强制踢出组,触发 Rebalance。 我们之前处理大订单消息时,单条消息处理要 6 分钟,直接触发消费超时,导致 Rebalance 频繁发生。 Rebalance 引起哪些问题 Rebalance 不是瞬间完成的,整个过程要经历注销旧分区→选举 Leader→分配新分区→消费者初始化,期间对业务的影响比你想的大。 1. 消费暂停,消息积压 Rebalance 期间,所有消费者都会暂停消费,等待新的分区分配。如果消费者组规模大(比如 100 个消费者、1000 个分区),Rebalance 可能持续几十秒,这段时间 Topic 消息只会堆积,下游服务拿不到数据。 所以在有消息积压的情况,优先看看是否有 Rebalance 的情况。 2. 消息重复和消息丢失 Rebalance 后,消费者重新拿到分区时,消费进度可能倒退:若没及时提交 offset(不管自动还是手动),会从最后一次提交的 offset 开始消费,中间没提交的消息要么重复处理,要么直接跳过,也就是消息重复消费和消息丢失的原因。 极端情况(比如 Coordinator 宕机),offset 存储的分区发生主从切换,可能导致 offset 数据错乱,进度直接回到几天前。 3. 资源浪费,负载不均 Rebalance 要靠 Coordinator 协调,频繁触发会占用 Kafka 集群的 CPU 和网络资源;而且 Kafka 默认的分区分配策略(Range 或 RoundRobin),很容易导致负载不均。 比如 5 个分区分配给 2 个消费者,可能出现 3 个分区 vs 2 个分区的情况,其中一个消费者压力翻倍,处理速度变慢,又会触发新的 Rebalance,陷入恶性循环。 什么情况下会丢数据 Rebalance 本身不会直接丢数据,但结合offset 提交和处理逻辑,很容易出现消息漏消费。 1.自动提交 offset + 消费没完成 Kafka 默认自动提交 offset,提交时机是 poll 到消息后,等 5 秒(默认 auto.commit.interval.ms)自动提交。
阅读全文