数据源故障排查:Kafka消费者组问题、数据倾斜、背压问题、数据丢失与重复
各位同学,咱们今天聊点实在的。实时流计算里,数据源就是咱们的粮草。粮草出了问题,后面的计算再牛也是白搭。我这些年排查过的故障,十有八九都跟Kafka这块脱不了干系。今天就把我踩过的坑、总结的经验,一股脑倒给你们。
一、Kafka消费者组问题:你以为是网络断了?其实不是
消费者组的问题,说白了就是“谁该消费哪个分区”的分配问题。我见过太多团队,一发现消费延迟就怀疑网络,结果折腾半天,发现是消费者组配置出了问题。
1.1 消费者组再均衡风暴
什么是再均衡?就是消费者组里成员变了,Kafka要重新分配分区。这个过程会暂停消费。如果频繁触发,你的数据流就会像过山车一样,忽快忽慢。
核心原因:
- 消费者心跳超时(session.timeout.ms 设置太短)
- 消费者处理时间过长(max.poll.interval.ms 设置不合理)
- 消费者频繁加入/退出(网络抖动或GC停顿)
我曾经在一个金融风控项目里,凌晨三点被叫起来。用户说数据延迟了半小时。我一看日志,好家伙,消费者组在10分钟内触发了7次再均衡。最后发现是某个节点的GC停顿超过了max.poll.interval.ms,Kafka以为它挂了,就踢出去了。等它恢复,又加回来,反复折腾。
我的建议:
把 session.timeout.ms 设成 30秒,max.poll.interval.ms 设成 5分钟。别用默认值。默认值太激进,生产环境扛不住。
1.2 分区分配不均
消费者组里,如果每个消费者分配到的分区数不一样,就会出现“旱的旱死,涝的涝死”。
为什么会这样?
- 使用了 Range 分配策略,但主题分区数不是消费者数的整数倍
- 手动指定了分区分配,但没考虑负载均衡
我建议用 StickyAssignor 或者 CooperativeStickyAssignor。这两种策略能尽量保持分区分配稳定,减少再均衡的影响。
二、数据倾斜:你的集群在“假忙”
数据倾斜,就是某些分区数据量特别大,某些分区特别小。你看着集群CPU跑满了,以为在全力干活,其实只有几个节点在忙,其他节点在摸鱼。
2.1 如何发现数据倾斜?
看三个指标:
| 指标 | 正常情况 | 倾斜情况 |
|---|---|---|
| 各分区消息数 | 相差不超过20% | 某个分区是其他分区的10倍以上 |
| 消费者处理延迟 | 各消费者基本一致 | 某个消费者延迟特别高 |
| Kafka Broker负载 | 各Broker均匀 | 某个Broker磁盘IO打满 |
2.2 数据倾斜的常见原因
- Key设计不合理:比如用用户ID做Key,但某个大客户的数据量是普通客户的100倍
- 分区数太少:分区数小于消费者数,导致某些消费者空闲
- 消息体大小不均:某个分区消息体特别大,其他分区消息体很小
注意:不要以为分区数越多越好。分区数太多会导致文件句柄占用过多,也会影响性能。我一般建议分区数控制在 Broker 数量的 2-3 倍。
2.3 解决数据倾斜的方法
嗯,这里要注意,不是所有倾斜都能彻底解决。我们能做的是缓解:
- 加盐:在Key后面加随机数,把数据打散到更多分区
- 自定义分区器:根据业务逻辑,把大客户的数据单独路由到特定分区
- 增加分区数:如果分区数确实太少,可以增加分区,但要注意重新分配数据
三、背压问题:系统在“喘不过气”
背压,就是下游处理速度跟不上上游生产速度。你想想看,Kafka就像个水管,上游哗哗放水,下游排水口太小,水就会漫出来。
3.1 背压的表现
- 消费者Lag持续增长
- 消费者线程阻塞,GC频繁
- 内存使用率飙升,甚至OOM
3.2 背压的排查思路
我个人的习惯是,先看消费者Lag。如果Lag在增长,说明下游处理能力不足。这时候别急着加机器,先看看是不是代码有问题。
我曾经遇到一个案例,消费者每次处理一条消息都要查一次数据库。数据库响应慢,导致整个消费链路阻塞。后来改成批量处理,一次查100条,性能提升了10倍。
背压处理的三种策略:
- 削峰填谷:用消息队列缓冲,让下游按自己的节奏消费
- 限流:在上游控制生产速度,比如用令牌桶算法
- 降级:丢弃非关键数据,保证核心业务不中断
四、数据丢失与重复:最头疼的问题
数据丢失和重复,是实时计算里最让人头疼的问题。金融场景里,丢一条数据可能意味着几百万的损失。重复数据虽然没那么严重,但会导致统计结果不准。
4.1 数据丢失的原因
| 场景 | 原因 | 解决方案 |
|---|---|---|
| 生产者发送失败 | 网络超时、Broker宕机 | 开启 acks=all,重试次数设大 |
| 消费者提交偏移量 | 先提交偏移量,后处理消息 | 先处理消息,再提交偏移量 |
| Broker数据丢失 | 副本数不足,Leader宕机 | 设置 replication.factor >= 3 |
4.2 数据重复的原因
说白了,重复就是“至少一次”语义的副作用。消费者处理完消息,还没来得及提交偏移量就挂了。重启后,Kafka会重新发送这条消息。
怎么解决?
- 幂等性处理:在业务逻辑里做去重,比如用唯一ID判断是否处理过
- 事务性写入:用Kafka事务,保证消息生产和消费是原子操作
- 外部存储去重:用Redis或数据库记录已处理的消息ID
我的经验:金融场景里,我建议用“幂等性处理 + 外部存储去重”的组合。Kafka事务虽然强大,但性能开销大,而且配置复杂。除非你特别需要精确一次语义,否则别轻易用。
五、知识体系总览
下面这张图,是我梳理的本章知识体系。你可以把它当成排查故障的路线图。
这张图把四个核心问题串起来了。你排查故障的时候,就按这个顺序来:先看消费者组有没有问题,再看数据是否倾斜,然后检查背压,最后确认数据有没有丢或重复。别跳着查,容易漏掉关键线索。
好了,这一章的内容就到这儿。记住,Kafka的故障排查,七分靠监控,三分靠经验。多积累,多总结,你也能成为别人眼中的“救火队员”。