一、消息队列(Kafka)故障诊断全景图
说实话,Kafka 在生产环境里出问题,翻来覆去就那么几类。我做了这么多年中间件运维,遇到最多的就是 Broker 挂了、分区 Leader 选不出来、消费者组 Rebalance 异常,还有消息积压。今天咱们就把这四类问题掰开揉碎,讲讲怎么诊断、怎么恢复。
核心思路:先定位症状,再分析根因,最后给出恢复策略。别一上来就重启,那是新手干的事。
二、Broker 宕机:最基础也最头疼的问题
2.1 怎么判断 Broker 真的挂了?
别光看监控面板变红就慌了。我习惯先跑几个命令确认一下:
# 查看集群中所有 Broker 状态
./kafka-broker-api-versions.sh --bootstrap-server localhost:9092
# 查看特定 Broker 是否在 ZK 中注册
./zookeeper-shell.sh localhost:2181 ls /brokers/ids
# 查看 Controller 是谁
./zookeeper-shell.sh localhost:2181 get /controller
嗯,这里要注意:如果 ZK 里能看到 Broker ID,但客户端连不上,那可能是网络问题,不一定是 Broker 挂了。
2.2 宕机后的连锁反应
Broker 一挂,影响是链式的:
- 分区 Leader 重新选举 —— 这个我们后面细说
- 生产者和消费者连接断开 —— 客户端会报连接异常
- 副本同步滞后 —— 如果挂的是 Leader,Follower 需要追上进度
- 消息可能丢失 —— 如果 acks=0 或 acks=1,没来得及刷盘的消息就没了
避坑指南:我曾经遇到过一台 Broker 的磁盘写满了,但进程还在。监控显示 Broker 活着,但所有分区都报错。所以别只看进程存活,要检查磁盘、网络、文件描述符这些底层资源。
2.3 恢复策略
| 场景 | 恢复操作 | 注意事项 |
|---|---|---|
| 进程异常退出 | 检查日志 → 修复配置 → 重启 | 先看 server.log 和 gc.log |
| 磁盘故障 | 更换磁盘 → 从副本恢复数据 | 确保有至少一个 ISR 副本 |
| 内存溢出 | 调整 JVM 参数 → 重启 | 建议 -Xmx 不超过物理内存的 50% |
| 网络分区 | 检查网络设备 → 恢复连通性 | Broker 会自动重新加入集群 |
三、分区 Leader 选举失败:集群的「脑死亡」
说白了,分区没有 Leader,就像军队没有指挥官。生产者和消费者都找不到写入和读取的目标。
3.1 为什么会选举失败?
我总结了几种常见原因:
- ISR 列表为空 —— 所有副本都挂了,或者都落后太多
- Controller 挂了 —— 选举是由 Controller 触发的
- ZK 会话过期 —— Broker 和 ZK 失联了
- 网络抖动 —— 选举过程中网络不稳定
3.2 诊断命令
# 查看分区状态
./kafka-topics.sh --describe --topic my-topic --bootstrap-server localhost:9092
# 查看 Controller 状态
./kafka-leader-election.sh --bootstrap-server localhost:9092 --election-type preferred --topic my-topic --partition 0
# 查看 ZK 中分区信息
./zookeeper-shell.sh localhost:2181 get /brokers/topics/my-topic/partitions/0/state
个人经验:有一次我发现某个分区一直选不出 Leader,查了半天发现是 ZK 里该分区的状态数据损坏了。手动删除 ZK 节点后,Kafka 自动重建了分区状态。当然,这招有风险,建议先备份。
3.3 手动干预选举
如果自动选举失败,可以手动指定:
# 手动触发 Leader 选举
./kafka-leader-election.sh --bootstrap-server localhost:9092 \
--election-type unclean \
--topic my-topic \
--partition 0
注意:unclean 选举会选一个不在 ISR 中的副本当 Leader,可能导致数据丢失。我一般只在「丢数据比不可用好」的场景下才用这招。
四、消费者组 Rebalance 异常:最隐蔽的坑
Rebalance 本身不是坏事,但频繁 Rebalance 或者 Rebalance 卡住,那就是问题了。你想想看,消费者们正在愉快地消费,突然全部停下来重新分配分区,这期间消息就积压了。
4.1 常见异常表现
- 频繁 Rebalance —— 几分钟一次,甚至几秒一次
- Rebalance 超时 —— 消费者无法在规定时间内完成分区分配
- 消费者被踢出组 —— session.timeout.ms 内没发心跳
- 分区分配不均匀 —— 有的消费者忙死,有的闲死
4.2 诊断方法
# 查看消费者组状态
./kafka-consumer-groups.sh --bootstrap-server localhost:9092 \
--group my-group --describe
# 查看消费者组详情(包括每个消费者的分区分配)
./kafka-consumer-groups.sh --bootstrap-server localhost:9092 \
--group my-group --describe --members --verbose
# 查看 Rebalance 相关日志
grep "Rebalance" /var/log/kafka/consumer.log | tail -100
4.3 根因分析
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 频繁 Rebalance | 消费者处理太慢,心跳超时 | 增大 max.poll.interval.ms 或优化处理逻辑 |
| Rebalance 超时 | 分区数太多,消费者数太多 | 增大 rebalance.timeout.ms |
| 消费者被踢出 | 网络抖动,GC 停顿 | 增大 session.timeout.ms,优化 GC |
| 分配不均匀 | 使用了 Range 分配策略 | 改用 RoundRobin 或 Sticky 策略 |
我的经验:有一次线上频繁 Rebalance,查了半天发现是一个消费者的 GC 停顿太长,导致心跳超时。调整了 -Xmx 和 GC 算法后,问题解决。说白了,很多 Rebalance 问题根子在 JVM 上。
五、消息积压排查:从源头到终点
消息积压是最直观的问题——消费者跟不上生产者了。但积压的原因可能千奇百怪。
5.1 积压的几种类型
- 生产者侧积压 —— 生产速度远大于消费速度
- 消费者侧积压 —— 消费者处理能力不足
- 网络积压 —— 带宽不够,数据传输慢
- 磁盘积压 —— 磁盘 I/O 成为瓶颈
5.2 排查命令
# 查看每个分区的 Lag
./kafka-consumer-groups.sh --bootstrap-server localhost:9092 \
--group my-group --describe
# 查看 Topic 的写入速率
./kafka-run-class.sh kafka.tools.JmxTool \
--object-name kafka.server:type=BrokerTopicMetrics,name=MessagesInPerSec
# 查看消费者消费速率
# 在消费者端打印每秒处理的消息数
5.3 恢复策略
我一般按这个优先级处理:
- 扩容消费者 —— 增加消费者实例,注意分区数要够
- 优化消费逻辑 —— 批量处理、异步处理、减少外部调用
- 调整分区数 —— 增加分区数提高并行度
- 限流生产者 —— 如果下游实在扛不住,只能让上游慢点
- 临时跳过积压消息 —— 重置 offset 到最新位置(会丢消息,慎用)
避坑指南:我曾经为了快速解决积压,直接给 Topic 加了 10 个分区。结果消费者组 Rebalance 了 5 分钟,积压更严重了。所以扩容前一定要评估 Rebalance 的影响。
六、总结:故障诊断的「三板斧」
做了这么多年,我总结了一套通用的诊断流程:
- 看日志 —— server.log、controller.log、consumer.log,日志里啥都有
- 看监控 —— 磁盘、网络、CPU、内存、GC,一个都不能少
- 看指标 —— Lag、吞吐量、请求延迟、连接数
嗯,其实大部分问题都能在这三步里找到答案。如果还找不到,那就看看是不是 ZK 的问题——很多 Kafka 的「疑难杂症」,根子都在 ZK 上。
最后说一句:别怕出问题,怕的是出了问题不知道怎么查。把这四类问题的诊断方法记熟了,Kafka 运维你就入门了。