上一篇【第82篇】Kafka性能调优完全指南——从生产者到消费者的全链路优化下一篇【第84篇】Kafka安全生产实战——TLS加密、SASL认证、ACL授权全套配置摘要生产环境最怕的还不是Kafka挂了——而是Kafka没挂但消息就是发不出去/消费不到/积压了10亿条。这些问题往往隐蔽而且排查方向不对的话排查8小时也找不到根因。本文是Kafka故障排查的急诊手册——10类生产环境最常见问题每一类都给出了排查决策树先查什么再查什么最后查什么并附上根因分析和根治方案。建议打印出来贴在显示器边上出问题先翻这篇。一、消息发送失败——排查决策树故障现象应用日志中出现大量RecordTooLargeException、TimeoutException、NotLeaderForPartitionException或NetworkException。排查决策树【消息发送失败 排查决策树】 Step 1检查错误类型看异常类名 │ ├── RecordTooLargeException │ → 消息太大超过 max.message.bytes │ → 解决调大服务端 max.message.bytes 或压缩消息 │ ├── TimeoutException │ → 进入 Step 2 │ ├── NotLeaderForPartitionException │ → Leader 切换中重试即可retries 0 │ → 检查是否频繁 Leader 切换ISR 不稳定 │ └── NetworkException / UnknownTopicOrPartitionException → 进入 Step 3 Step 2TimeoutException 深度排查 │ ├── 检查 acks 配置 │ ├── acksall 且 min.insync.replicas 1 │ │ → ISR 副本不足写入被阻塞 │ │ → 解决恢复 ISR 副本 或 临时调小 min.insync.replicas │ └── acks1 或 0 │ → 进入网络检查 │ ├── 检查 request.timeout.ms默认 30000 │ → 如果网络慢适当调大到 60000 │ └── 检查 Broker 负载CPU/磁盘 IO → kafka-broker-*.log 中是否有 Too many open files Step 3网络连通性排查 │ ├── telnet broker-host 9092 │ → 不通防火墙/安全组问题 │ ├── 检查 advertised.listeners 配置 │ → Broker 注册到 ZK 的地址客户端能否访问 │ → 常见坑容器内跑 Kafkaadvertised.listeners 配了容器 IP │ └── 检查 Producer 的 bootstrap.servers → 是否配了已下线的 Broker根治方案速查表错误类型根因根治方案RecordTooLargeException消息超 max.message.bytes压缩消息 / 调大 max.message.bytes / 拆分大消息TimeoutException(acksall)ISR 不足恢复故障 Broker / 检查 min.insync.replicasTimeoutException(acks1)网络慢 / Broker 慢调大 request.timeout.ms / 优化 BrokerNotLeaderForPartitionExceptionLeader 切换确保 retries 0 / 排查频繁 Leader 切换根因NetworkException网络不通检查防火墙 / advertised.listeners / bootstrap.serversUnknownTopicOrPartitionExceptionTopic 不存在或分区正在选举自动创建 Topic 或预先创建 / 等待选举完成二、消费者不消费——排查决策树故障现象应用启动了但kafka-consumer-groups.sh --describe显示CURRENT-OFFSET不变化Lag 只增不减。排查决策树【消费者不消费 排查决策树】 Step 1消费者进程是否存活 │ ├── 进程挂了 → 重启检查为何挂OOM │ └── 进程存活 → 进入 Step 2 Step 2消费者是否还在 Group 中有没有被踢出 │ ├── kafka-consumer-groups.sh --describe │ → CONSUMER-ID 列为空 → 消费者已被踢出 Group │ → 原因session.timeout.ms 太短心跳没发出来 │ → 解决调大 session.timeout.ms默认 10000 → 30000 │ └── CONSUMER-ID 有值 → 进入 Step 3 Step 3消费者是否在持续 poll() │ ├── 应用日志中是否有异常处理消息时抛异常导致 offset 没提交 │ → 常见反序列化失败 → 消息格式不对 / 有脏数据 │ → 解决加 try-catch脏数据写 DLQ │ ├── 消费者是否陷入了无限 Rebalance │ → 日志中频繁出现 Attempt to heartbeat failed │ → 解决检查 max.poll.interval.ms 是否小于处理时间 │ └── 消费者 poll() 正常但就是不提交 offset → enable.auto.commitfalse 时是否忘了手动 commit → 解决确保在处理完成后调用 commitSync() 或 commitAsync()一个经典坑反序列化失败导致假死// 错误示范反序列化失败整个消费循环卡死while(true){ConsumerRecordsK,Vrecordsconsumer.poll(Duration.ofMillis(100));for(ConsumerRecordK,Vrecord:records){// 如果某条消息格式不对这里抛异常// 异常被外层 catch 吞掉offset 没提交下次还是消费同一条 → 死循环process(record);}consumer.commitSync();}// 正确示范捕获单条消息的异常跳过脏数据while(true){ConsumerRecordsK,Vrecordsconsumer.poll(Duration.ofMillis(100));for(ConsumerRecordK,Vrecord:records){try{process(record);}catch(Exceptione){log.error(处理消息失败, offset{}, 写入 DLQ,record.offset(),e);sendToDLQ(record,e);// 不重新抛异常继续处理下一条}}consumer.commitSync();}三、Rebalance 频繁——根因分析故障现象应用日志中频繁出现Revoking previously assigned partitions、Partitions reassigned消费时断时续Lag 持续增长。六大根因【Rebalance 频繁的 6 大根因】 根因1session.timeout.ms 太短 处理时间间隔 → 消费者心跳没来得及发就被 GroupCoordinator 踢出 → 症状日志中有 Attempt to heartbeat failed since the consumer is not part of the group → 根治session.timeout.ms 3000030秒heartbeat.interval.ms 3000 根因2max.poll.interval.ms 太短 一批消息的处理时间 → 消费者处理太慢超时没调用 poll()被踢出 Group → 症状日志中有 Consumer was kicked out of the group → 根治max.poll.interval.ms 60000010分钟或减少 max.poll.records 根因3消费者处理时间不稳定GC 停顿 / 下游依赖慢 → 某次处理卡了 40 秒超过 session.timeout.ms → 根治优化处理逻辑 / 异步处理 / 调大 session.timeout.ms 根因4PartitionAssignor 选择不一致 → 新旧消费者用的 Assignor 不一样导致每次 Rebalance 都重新分配 → 根治所有消费者显式配置相同的 partition.assignment.strategy 根因5Topic 分区数变了运维操作 → 分区数增加会触发 Rebalance → 根治通知下游或在低峰期操作 根因6Group 中加入了新消费者实例 → 扩缩容会触发 Rebalance这是正常行为 → 缓解使用 StickyAssignor尽量减少分区迁移推荐配置根治 Rebalance 频繁// 消费者端推荐配置根治 Rebalance 频繁props.put(session.timeout.ms,30000);// 30秒足够长props.put(heartbeat.interval.ms,3000);// 3秒默认 3秒不用改props.put(max.poll.interval.ms,600000);// 10分钟处理时间再长也不怕props.put(max.poll.records,500);// 控制每次处理的数量避免超时props.put(partition.assignment.strategy,org.apache.kafka.clients.consumer.StickyAssignor);// 粘性分配减少迁移四、Broker OOM——排查与根治故障现象Kafka Broker 进程突然退出日志末尾出现java.lang.OutOfMemoryError: Java heap space或进程还活着但完全不响应请求。排查决策树【Broker OOM 排查决策树】 Step 1确认是 Heap OOM 还是 Off-heap OOM │ ├── 日志中有 Java heap space │ → Heap 不够用 │ → 进入 Step 2 │ └── 日志中有 Direct buffer memory 或 Unable to create new native thread → Off-heap 不够用 → 进入 Step 3 Step 2Heap OOM 排查 │ ├── 检查 Broker 的堆内存配置KAFKA_HEAP_OPTS │ → 默认可能只有 1G生产环境至少 4G~8G │ → 修复export KAFKA_HEAP_OPTS-Xms8g -Xmx8g │ ├── 是否有大消息 1MB │ → 大消息会撑爆堆特别是在批处理中 │ → 修复限制消息大小max.message.bytes或拆分 │ └── 是否开启了 SSL 且连接数很多 → SSL 握手需要较多堆内存 → 修复调大堆 / 减少连接数 / 使用连接复用 Step 3Off-heap OOM 排查 │ ├── 检查 Direct Memory 限制-XX:MaxDirectMemorySize │ → 默认等于堆大小但 SSL 零拷贝会大量使用堆外内存 │ → 修复显式设置 -XX:MaxDirectMemorySize4g │ └── 是否使用了 Compression → 解压缩需要堆外内存 → 修复减少并发压缩连接数生产环境 Broker JVM 推荐配置# kafka-server-start.sh 中或在环境变量中设置exportKAFKA_HEAP_OPTS-Xms8g -Xmx8g# 堆内存固定大小避免动态扩容exportKAFKA_JVM_PERFORMANCE_OPTS -XX:UseG1GC -XX:MaxGCPauseMillis20 -XX:InitiatingHeapOccupancyPercent35 -XX:G1HeapRegionSize16m -XX:MaxDirectMemorySize4g 五、ISR 频繁收缩——根因分析故障现象Broker 日志中频繁出现Partition [topicName,partitionId] marked as failed或 ISR 列表频繁变动-箭头在 ISR 变化时输出。用kafka-topics.sh --describe看到 ISR 数量不断变少又变多。根因分析【ISR 频繁收缩的根因】 根因1Follower 拉取速度跟不上 Leader → Follower 的网络或磁盘 IO 有瓶颈 → 症状Follower 的 LEO 与 Leader 的 LEO 差距持续增大 → 修复检查 Follower 所在 Broker 的磁盘 IOiostat -x 1 → 如果磁盘 IO 慢迁移该 Broker 上的分区 根因2Broker 频繁 Full GC → GC 停顿期间Follower 无法向 Leader 发送 Fetch 请求 → ISR 收缩 → GC 完后恢复 → ISR 扩张反复横跳 → 修复优化 Broker JVMG1GC固定堆大小 根因3Broker 网络带宽打满 → Follower 无法及时从 Leader 拉取数据 → 修复限制生产者吞吐quota或扩容网络 根因4replica.lag.time.max.ms 设置太短默认 30000 → Follower 哪怕只慢了 30 秒就被踢出 ISR → 修复调大到 60000特别是在跨机房部署时 根因5unclean.leader.election.enabletrue危险 → ISR 为空时允许非 ISR 副本成为 Leader → 数据丢失 → 修复设为 false生产环境必须ISR 监控告警# 关键 JMX 指标kafka.server:typeReplicaManager,nameUnderReplicatedPartitions# 这个值 0 说明有分区 ISR 不足# 用 Prometheus JMX Exporter 监控# Prometheus 查询kafka_server_replicamanager_underreplicatedpartitions0# 告警规则- alert: UnderReplicatedPartitions expr: kafka_server_replicamanager_underreplicatedpartitions0for: 5m# 持续 5 分钟才告警避免网络抖动误报六、ZooKeeper 连接问题——排查与根治注意Kafka 2.8 开始支持 KRaft 模式去 ZooKeeper建议新集群使用 KRaft 模式彻底避免 ZK 问题。故障现象Broker / 客户端日志中出现ZooKeeperClientTimeoutException、ConnectionLoss、SessionExpired。排查决策树【ZooKeeper 连接问题 排查决策树】 Step 1ZooKeeper 集群本身是否健康 │ ├── echo ruok | nc zk-host 2181 → 返回 imok 才正常 │ ├── ZooKeeper 是否有 Leader │ → echo stat | nc zk-host 2181 │ → Mode: leader / follower / standalone │ → 如果没有 Leader选举中等待选举完成 │ └── ZooKeeper 磁盘是否慢 → ZK 对磁盘 IO 极其敏感它是同步写磁盘的 → 修复ZK 数据目录必须放在 SSD 上 Step 2ZooKeeper 与 Broker 之间的网络是否正常 │ ├── ping zk-host │ → 延迟 50ms 就危险了 │ └── 是否有大量连接 → ZK 的 maxClientCnxns 默认 60不够用就调大 → 修复zoo.cfg 中加 maxClientCnxns2000 Step 3Broker 的 ZK 会话超时设置是否合理 │ ├── zookeeper.session.timeout.ms默认 18000 │ → 如果 ZK 压力大适当调大到 30000 │ └── 是否有频繁 Full GC → GC 导致心跳没发出去ZK 会话过期 → 修复优化 Broker JVM七、磁盘空间耗尽——紧急处理故障现象Broker 日志中出现No space left on device或者操作系统df -h显示 Kafka 数据目录磁盘使用率 100%。紧急处理 SOP# Step 1紧急清理旧数据先删 oldest segment不要删整个 partition# 找到占用最大的 Topicdu-sh/data/kafka-logs/*|sort-rh|head-20# Step 2临时调小 retention 时间触发快速清理kafka-configs.sh--alter\--topic占用最大的topic\--add-configretention.ms3600000\# 临时改为 1 小时--bootstrap-server localhost:9092# Step 3等待 Log Cleaner 线程清理可能需要几分钟# 监控磁盘使用率watch-n5df -h /data# Step 4清理完成后恢复原 retention 配置kafka-configs.sh--alter\--topictopic名\--add-configretention.ms604800000\# 恢复 7 天--bootstrap-server localhost:9092# Step 5根治 —— 增加分区数分散到更多 Broker/磁盘# 或者增加 Broker 节点做分区重分配八、Controller 频繁切换——排查故障现象kafka-controller.log中频繁出现Broker [id] was elected as the controller或者kafka-broker.log中出现Controller moved to another broker。根因与修复【Controller 频繁切换的根因】 根因1ZooKeeper 会话频繁过期 → 同问题六的排查 → 根治优化 ZK 性能SSD/ 调大 ZK 会话超时 根因2Controller 所在的 Broker 频繁 Full GC → Controller 是单线程处理的GC 停顿期间无法处理请求 → 其他 Broker 认为 Controller 死了触发重新选举 → 根治优化 Controller 所在 Broker 的 JVM 根因3Controller 所在 Broker 网络不稳定 → 其他 Broker 收不到 Controller 的心跳 → 根治将 Controller 部署在网络更稳定的 Broker 上 Kafka 没有指定 Controller的功能但可以通过 先停掉其他 Broker、只留目标 Broker让目标 Broker 成为 Controller 再启动其他 Broker 的方式来诱导 根因4KRaft 模式Active Controller 频繁切换 → 检查 KRaft Quorum 中节点的网络连通性 → 检查 metadata.log 是否损坏九、生产消息顺序错乱——排查故障现象发送端按顺序发送msg1, msg2, msg3但消费端看到的顺序是msg2, msg1, msg3。根因分析【消息顺序错乱的根因】 根因1使用了自定义 Partitioner且分区逻辑导致同一 Key 的消息去了不同分区 → Kafka 只保证分区内有序不保证跨分区有序 → 修复确保需要顺序的消息同一订单 ID去同一个分区 → 使用 DefaultPartitioner 指定消息 Key 即可 根因2开启了幂等enable.idempotencetrue但 max.in.flight.requests.per.connection 5 → 幂等 Producer 在 inflight 5 时会退化为非幂等 → 可能导致 Broker 端的重试引起乱序 → 修复max.in.flight.requests.per.connection 5默认 5开启幂等时是安全的 根因3Producer 端重试 → 消息1 发送失败重试消息2 发送成功 → 消费端先看到消息2再看到消息1 → 修复max.in.flight.requests.per.connection1严格顺序但吞吐量下降 → 或者允许短暂乱序业务层做去重/排序十、消费组 CommitFailedException——根因与修复故障现象消费者日志中出现CommitFailedException: Commit cannot be completed since the group has already rebalanced。根因消费者在调用commitSync()之前GroupCoordinator 已经发起了 Rebalance因为该消费者被认为死亡了。修复方案// 方案1调大 max.poll.interval.ms最常用props.put(max.poll.interval.ms,600000);// 10分钟内必须完成处理提交// 方案2减少 max.poll.records让每次 poll() 处理更快props.put(max.poll.records,200);// 每次只处理 200 条// 方案3使用 StickyAssignor减少 Rebalance 时的分区迁移开销props.put(partition.assignment.strategy,org.apache.kafka.clients.consumer.StickyAssignor);// 方案4捕获 CommitFailedException不中断消费循环while(true){ConsumerRecordsK,Vrecordsconsumer.poll(Duration.ofMillis(100));processRecords(records);try{consumer.commitSync();}catch(CommitFailedExceptione){log.warn(提交偏移量失败可能发生了 Rebalance下次会重新消费,e);// 不抛异常继续循环下次 poll() 会先重新加入 Group}}本篇小结本文系统梳理了 Kafka 生产环境 10 类最常见故障的排查方法消息发送失败先看异常类型区分是消息太大、ISR 不足、还是网络不通消费者不消费先确认进程存活 → 是否在 Group 中 → 是否持续 poll() → 是否有异常处理导致 offset 没提交Rebalance 频繁六大根因session 超时 / poll 超时 / GC 停顿 / Assignor 不一致 / 分区数变化 / 扩缩容逐一排查Broker OOM区分 Heap OOM调大 -Xmx和 Off-heap OOM调大 MaxDirectMemorySizeISR 频繁收缩Follower 慢 / Broker GC / 网络带宽 / replica.lag.time.max.ms 太短四大根因ZK 连接问题先查 ZK 集群健康 → 再查网络 → 最后查会话超时配置建议新集群用 KRaft 模式彻底避免磁盘空间耗尽紧急 SOP——临时调小 retention → 触发清理 → 恢复原配置 → 根治扩分区/扩 BrokerController 频繁切换ZK 会话过期 / Controller 的 Broker GC / 网络不稳定消息顺序错乱确保同一 Key 去同一分区 max.in.flight.requests.per.connection 5CommitFailedException调大 max.poll.interval.ms 或减少 max.poll.records上一篇【第82篇】Kafka性能调优完全指南——从生产者到消费者的全链路优化下一篇【第84篇】Kafka安全生产实战——TLS加密、SASL认证、ACL授权全套配置