Kafka部分partition leader=-1故障排查与修复指南

发布时间:2026/10/26 12:56:28
Kafka部分partition leader=-1故障排查与修复指南 凌晨两点被值班电话叫醒打开监控面板某个核心 topic 的 12 个 partition 里有 3 个的 Leader 列显示-1ISR 那一栏是空的消费端 lag 曲线直接拉成一条横线。这种场景对做过 Kafka 集群运维的人来说一点都不陌生kafka 部分 partition 的 leader-1本质上是 controller 没有给这几个 partition 指派有效 leader元数据里的 leader 字段被写成了 -1。它既可能是 broker 全挂后的短暂空窗也可能是副本目录损坏、ISR 清空、controller 卡死这类硬故障的表象。这篇内容我按先搞懂它是什么 → 分层定位到具体原因 → 分场景给出可执行的修复动作 → 参数取舍 → 速查表与踩坑的顺序整理把能直接抄作业的命令和判断逻辑都放进去。读者对象很明确手里管着 Kafka 集群、需要在故障窗口内快速判断该等还是该动手的后端和运维同学以及想搞明白副本选举机制到底怎么跑的开发同学。下面开始。1. 先把 leader-1 这件事拆干净1.1 leader、ISR、AR 三个词的关系速览在动手之前把三个概念的关系捋顺后面所有判断都建立在这个基础上。ARAssigned Replicas是创建 topic 时定下来的副本排班表比如 partition 3 的 AR 是[1,2,4]意思是这份数据在 broker 1、2、4 上各存一份除非做重分配否则这个列表不会变。ISRIn-Sync Replicas是 AR 里当前跟得上 leader的那部分副本是动态的follower 拉取落后超过replica.lag.time.max.ms就会被踢出去追上来了又会加回来。Leader只能从 ISR 里选因为只有 ISR 里的副本才保证数据基本完整选它当 leader 才不会丢掉已经提交的消息。打个生活化的比方AR 是排班表上写名字的所有人ISR 是此刻真的在岗的人leader 是值班长。值班长必须从在岗的人里挑因为不在岗的人根本不知道今天发生了什么事。如果排班表上的人一个都没来那值班长的位置就空着——这个空着在 Kafka 的元数据里就表示成leader -1。所以看到 -1第一反应不应该是Kafka 坏了而应该是这几个 partition 的 AR 里一个可用的副本都没有。这里要强调一个容易混淆的点leader-1 不等于 partition 不存在也不等于 topic 被删了。用kafka-topics.sh --describe依旧能列出这个 partitionAR 列表照样完整只是 leader 和 ISR 是空的。数据文件大概率还安安静静躺在磁盘上只是暂时没有人被授权对外提供服务。理解这一点很重要因为它决定了修复方向是让人重新上岗而不是重建数据。1.2 leader-1 在元数据里到底是什么样子要看清楚它的真面目得下钻到元数据层。ZooKeeper 模式下每个 partition 的 leader/ISR 信息存在一个固定路径/brokers/topics/topic名/partitions/分区号/state。用zookeeper-shell.sh连上去get一下内容大概长这样{controller_epoch:128,leader:-1,version:1,leader_epoch:-1,isr:[]}这里面几个字段各有含义。controller_epoch是当前 controller 的任期号每次 controller 切换它会自增用来防止旧 controller 的过期指令生效。leader是 -1 就说明没有 leader。isr为空数组说明连一个同步副本都没有。整个 JSON 是 controller 在处理 broker 上下线事件时写进去的所以这个节点的内容直接反映了 controller 眼里的世界。KRaft 模式下没有 ZooKeeper这些信息被写进内部的__cluster_metadatatopic通过kafka-metadata-quorum.sh --bootstrap-server 地址 describe --status看集群元数据状态用kafka-dump-log.sh --cluster-metadata-decoder去解析快照和日志里的记录。虽然查看方式变了但判断逻辑完全一样leader 字段是不是 -1ISR 是不是空。客户端侧的表现也值得记一下因为它能帮你快速判断影响面。Producer 往这些 partition 写数据会收到LEADER_NOT_AVAILABLE或者新版本里的NOT_LEADER_OR_FOLLOWER如果配置了重试它会一直重试直到超时Consumer 这边更有意思它会卡在拉取阶段不动日志里刷LEADER_NOT_AVAILABLE但 lag 曲线反而不涨——因为它压根没消费到新数据。很多人第一次遇到会误判成消费端挂了其实根子在元数据。1.3 为什么偏偏是部分 partition标题里部分 partition这个限定词其实是一条极其重要的线索它直接缩小了排查范围。如果故障是集群级的比如 ZK 全线不可用、controller 挂了你看到的应该是大面积甚至全量的 leader-1而现在只有零星几个 partition 出问题说明故障被限制在某个局部。最常见的局部性原因是副本分布扎堆。假设一个 topic 是 3 副本做重分配的时候没注意 broker 分布把 partition 3 的三个副本全放在了 broker 1、2、3 上而这三台机器恰好共享同一个机柜的电源或者同一块存储。电源一抖三台一起掉这个 partition 的 AR 全军覆没leader 自然是 -1而其他 partition 因为副本分散在别的机器上早就自动切走了。这也是为什么broker.rack这个配置不是可选项——跨机架分布不是锦上添花是防止部分 partition 集体阵亡的基本盘。第二种常见情况是单副本 topic。有些团队为了省存储把日志类、埋点类的 topic 设成replication.factor1。这种 topic 只要它所在的 broker 一重启partition 立刻变成 leader-1而且没有任何自愈能力因为根本没有第二个副本可以顶上来。这类 topic 平时不出事一出事就是硬故障我在好几个集群里都见过这种埋了很久的雷。第三种是磁盘或目录级别的局部损坏。broker 进程活着、ZK 注册也正常但某几个 partition 的日志目录因为磁盘坏道、挂载点掉线、权限变更导致读不出来broker 启动扫描时会把它们标记为不可用controller 收到汇报后就把对应 partition 的 leader 置为 -1。这种故障的特征是进程健康、节点在线、但就是有那么几个分区起不来用kafka-log-dirs.sh一查就能看出端倪。2. 分层排查从元数据到磁盘的五层下钻2.1 第一层确认影响面与业务表现排查的第一步永远是量化影响面别一上来就重启。先把所有 leader-1 的 partition 捞出来看它们有什么共性。最直接的办法是kafka-topics.sh --bootstrap-server broker1:9092 --describe \ | awk -F\t $3 ~ /Leader: -1/ {print $2, $3, $4, $6}不同版本的--describe输出列数不完全一样字段位置会有偏差所以更稳妥的写法是先跑一遍看原始输出长什么样再决定 awk 取哪一列。输出里你会拿到 partition 编号、Leader 信息、Replicas 列表、Isr 列表这四样东西重点看Replicas 这一列。如果这几个出问题的 partition 的 Replicas 列表高度重合比如都是1,2,3那基本可以断定是这三台 broker 出了共同问题。如果 Replicas 各不相同、分散在不同 broker 上那问题更可能出在 controller 或者元数据一致性上而不是某一台机器。这个判断会决定你后面走哪条分支别跳过。同时看一眼业务侧的表现把技术指标和业务感受对上Producer 的错误率是不是只在这几个 partition 上飙升Consumer 是卡住还是在空转有没有 topic 的消息写入完全停滞但其他 topic 正常这些信息组合起来能帮你判断是只影响这一批分区还是已经开始扩散。2.2 第二层Broker 存活与注册状态确认了影响面之后直接去看 broker 的注册状态。ZK 模式下zookeeper-shell.sh zk1:2181 ls /brokers/ids这条命令返回的是当前活着并且被 controller 认可的 broker id 列表。拿它跟集群实际配置的 broker 清单对比缺了谁一目了然。然后再get /brokers/ids/id看看节点内容里面会有endpoints、rack、timestamp这些信息能帮你确认这台机器的注册信息有没有异常。这里有个特别容易踩的坑进程活着不等于已注册。Kafka broker 和 ZK 之间靠会话维持心跳如果发生长时间 Full GC、网络分区、ZK 端负载过高会话可能超时ZK 会自动删掉/brokers/ids/id节点controller 收到通知后认为这台 broker 死了把它上面的 leader 全部切走如果某些 partition 的副本全在这台机器上就直接 leader-1。而你jps一看进程明明还在日志也在刷很容易误判成broker 是好的问题在别处。反过来也有假活broker 进程已经 OOM 被杀了但 ZK 会话还没到期默认zookeeper.session.timeout.ms是 18000 毫秒节点还挂在上面controller 暂时不知道它死了这段时间内它上面的 leader 不会被切换客户端连过去会超时。所以判断 broker 状态一定要进程、ZK 节点、controller 视图三方对齐只看一个都会误判。KRaft 模式下对应的是kafka-metadata-quorum.sh --bootstrap-server 地址 describe --status看 quorum 成员状态以及--replication看各节点的日志复制进度。2.3 第三层副本目录与日志段的物理完整性broker 状态没问题那就往下走一层看数据本身。Kafka 的日志目录结构是log.dirs/topic名-分区号/比如foo-3/里面应该包含至少一个.log段文件、配套的.index和.timeindex加上leader-epoch-checkpoint、partition.metadata这几个文件。去对应 broker 上看一眼这个目录在不在、里面有没有东西。比手工 ls 更好用的是官方工具kafka-log-dirs.sh --bootstrap-server broker1:9092 --describe --topic-list foo它会以 JSON 形式返回每个 broker 上每个副本的size、offsetLag、isFuture。这里的关键判读方式如果某个副本的size是 0说明这个目录是空的或者刚被创建broker 手里根本没有这个分区的数据自然不可能进 ISR如果offsetLag是 -1通常表示这个副本当前不可用。把 size 为 0 的副本挑出来跟 AR 列表比对你就知道到底有几份真数据还活着。目录为空的原因很多新建 broker 后忘记迁移数据、挂载盘没挂上导致 Kafka 在系统盘上新建了空目录、人为误删、容器化部署时 PV 挂载失败。这些场景我全见过尤其容器环境一个 PV 挂载顺序问题就能让 broker 起来后所有分区都是空的表现就是大面积 leader-1。2.4 第四层Controller 与元数据一致性副本都健康但 leader 就是不选出来这时候怀疑对象该转向 controller 了。ZK 模式下先看 controller 是谁zookeeper-shell.sh zk1:2181 get /controller返回的 JSON 里有brokerid和version其中 version 就是 controller_epoch。连续观察几次如果 epoch 一直在涨说明 controller 在频繁切换这本身就是大问题。频繁切换的典型原因是 ZK 集群不稳定比如 ZK 自身在做 leader 选举、或者 controller 所在 broker 的 GC 停顿太长导致会话超时。再看 controller 所在 broker 的controller.log搜几个关键词Leader election看选举有没有失败Unable to elect看有没有明确报错Controller moved to看切换记录。如果日志里出现大量Notifying broker ... of partition state change之后紧跟异常往往能定位到具体是哪个 broker 的哪个 partition 让 controller 处理不下去了。还有一种情况值得单独提controller 卡在某个耗时操作上。比如集群刚做完大规模重分配controller 在处理成千上万个 partition 的状态变更CPU 打满新的上下线事件排在队列里处理不过来表现出来的就是broker 已经恢复了但 leader 迟迟不回来。这种不需要动任何配置等它处理完就好判断依据是 controller 的线程栈里能看到kafka.controller包的调用栈在持续工作。2.5 第五层磁盘、句柄、权限这些非 Kafka 问题前面四层都干净那问题很可能根本不在 Kafka 层面。这一层查的是操作系统。磁盘最先看df -h扫一遍所有log.dirs所在的分区。Kafka 不会因为磁盘满就直接退出它的表现更阴险写入失败导致 segment 无法正常滚动follower 拉不到新数据replica.lag.time.max.ms一到就被踢出 ISRISR 缩到 0 就成了 leader-1。整个过程进程一直是活的监控上 CPU、内存都正常只有磁盘使用率在悄悄逼近 100%。然后是 inodedf -i看一眼。Kafka 每个 segment 至少三个文件日志量大、segment 小的集群很容易把 inode 耗尽症状和磁盘满几乎一样。再往下是文件句柄ulimit -n和/proc/pid/limits对一下句柄耗尽时会报Too many open filesbroker 打不开新的 segment 文件行为同样诡异。权限问题也别忘了。如果 log.dirs 的属主被改过比如有人用 root 手动拷过数据Kafka 进程启动后能读不能写或者干脆读不了日志里会有明确的Permission denied。至于挂载点掉线云上环境尤其常见一块盘无声无息地 unmont 了Kafka 还以为是空的等到要写才发现路径不存在。这类问题的日志特征很明确搜IOException、No space left on device、Too many open files、Input/output error、Permission denied这几个关键词基本一搜一个准。3. 分场景修复动作与实操记录3.1 场景一副本所在 Broker 全部离线后恢复这是最常见、也最温和的一种。特征很明确leader-1 的那几个 partitionAR 列表里的 broker id 全部落在同一台或同一批同时挂掉的机器上而其他 partition 一切正常。触发原因可能是 broker 重启、机器故障、机房网络抖动。修复流程其实大部分时候不需要你做什么。把 broker 拉起来它会重新向 ZK 注册KRaft 下是重新加入 quorumcontroller 收到BrokerChange事件后会检查这台 broker 上所有副本的 ISR对每个副本所在的 partition 触发一次 leader 选举。只要这个 broker 上的副本数据完整、能正常打开几秒到几十秒内 leader 就会回来ISR 也会重新填充。如果等了一两分钟还没回来先别急着上工具先确认两件事一是 broker 有没有真的注册成功回到 2.2 层去查二是这个 partition 的 ISR 是不是依旧为空。如果 ISR 已经有内容但 leader 还是 -1那就是 controller 没感知到变化可以用 preferred 选举主动触发一下kafka-leader-election.sh --bootstrap-server broker1:9092 \ --election-type PREFERRED --topic foo --partition 3注意PREFERRED选举的作用是把 leader 挪回 AR 列表里的第一个副本它要求 ISR 非空解决不了 ISR 为空的问题。很多人在这里搞混以为跑一遍 preferred 选举就能救场结果命令执行成功但 leader 依旧是 -1白白浪费故障窗口。判断标准很简单先看 ISRISR 空就往下走场景二ISR 不空才用 PREFERRED。3.2 场景二ISR 为空靠 unclean 选举救回来这是真正需要做决策的场景。AR 里还有活着的 broker但 ISR 是空数组意味着没有一个副本能证明自己跟得上原 leader。这时候默认配置下 controller 是拒绝选 leader 的因为它无法保证选出来的副本数据完整。先确认前提条件AR 列表里至少有对应的 broker 是活着的且它的日志目录里有实际数据kafka-log-dirs.sh里 size 大于 0。如果所有副本的数据目录都是空的那 unclean 选举也救不了只能重建 topic这一点必须先想清楚。确认能救之后临时打开 unclean 开关。建议在 topic 级别改影响面最小kafka-configs.sh --bootstrap-server broker1:9092 --alter \ --entity-type topics --entity-name foo \ --add-config unclean.leader.election.enabletrue然后触发 unclean 选举可以指定单个分区也可以用 JSON 文件批量kafka-leader-election.sh --bootstrap-server broker1:9092 \ --election-type UNCLEAN --topic foo --partition 3批量的话准备一个文件{version:1,partitions:[{topic:foo,partition:3},{topic:foo,partition:7}]}kafka-leader-election.sh --bootstrap-server broker1:9092 \ --election-type UNCLEAN --path-to-json-file /tmp/election.json选举成功后leader 会立刻变成那个存活副本的 broker idISR 里也只有它自己。接下来它会开始接受写入其他副本恢复后会重新追上并加回 ISR。这里必须提醒风险unclean 选出来的 leader 可能是落后了几个小时的副本它一旦开始对外服务原来 leader 上那些没同步过去的消息就永久丢失了。所以这个操作必须经过业务方确认尤其是涉及订单、支付这类不能丢数据的 topic宁可等副本恢复也不要贸然开。修完之后有两件事一定要做。第一把 topic 级别的开关删掉kafka-configs.sh --bootstrap-server broker1:9092 --alter \ --entity-type topics --entity-name foo \ --delete-config unclean.leader.election.enable第二等 ISR 恢复到正常副本数之后跑一次 preferred 选举把 leader 分布拉回均衡。这个开了忘关是重灾区我见过有集群因为一次故障临时开了全局 unclean之后再没人管两年后另一次故障里悄无声息地丢了一批数据复盘时才发现根子在这里。3.3 场景三单个副本目录损坏走重分配而不是硬删如果kafka-log-dirs.sh显示某个副本 size 为 0 或 offsetLag 异常说明这一份数据坏了。这时候有两种处理思路优先级差别很大。推荐做法是用重分配把这个副本迁走或者从 AR 里剔除。先在脑子里确认一遍目标分布如果原来是[1,2,4]broker 4 上的副本坏了可以改成[1,2,5]让 broker 5 重新拉一份完整数据。生成计划{version:1,partitions:[ {topic:foo,partition:3,replicas:[1,2,5],log_dirs:[any,any,any]} ]}kafka-reassign-partitions.sh --bootstrap-server broker1:9092 \ --reassignment-json-file /tmp/reassign.json --execute --throttle 50000000--throttle的单位是字节每秒这里设的是 50MB/s 的单 broker 迁移限速。不设这个参数是新手最常犯的错误之一一个大 partition 全速迁移能把整个机架的带宽吃满引发其他 broker 的 ISR 收缩把小故障放大成大故障。执行完之后用--verify持续观察进度看到completed才算完事。不推荐但有时候不得不用的做法是直接删目录停掉目标 brokerrm -rf掉那个 partition 目录重启让 broker 自己创建一个空副本然后从 leader 拉数据。这个做法的问题在于如果删的这个副本恰好是 leader删除操作本身会触发一次 leader 切换如果删完之后发现 ISR 里只剩它一个那就直接掉进场景二。另外在容器化、自动化部署的环境里手工删目录很可能被编排系统覆盖回去。所以除非是单机测试环境或者实在没别的办法否则优先走重分配。3.4 场景四Controller 卡死或元数据残留这一层的问题通常更隐蔽。典型症状是 broker 明明已经注册了ls /brokers/ids能看到它但对应 partition 的 leader 就是不恢复controller.log 里也没什么明显报错。先排除 GC 因素去看 controller 所在 broker 的 GC 日志搜停顿时间超过 1 秒的记录。如果zookeeper.session.timeout.ms是默认的 18 秒而某次 Full GC 停了 20 秒controller 会话就断了ZK 会重新选一个 controller新 controller 上任后要重新加载全部元数据这段时间整个集群的 leader 选举都会停滞。等它加载完一切会自动恢复不需要人为干预。如果是真卡死了最稳妥的手段是重启 controller 所在的 broker。如果 controller 和 broker 混布默认就是这样重启会影响这台机器上的所有 leader但其他的会自动切换过去。想要更轻量的做法ZK 模式下可以删掉 controller 节点让它重新选举zookeeper-shell.sh zk1:2181 delete /controller这个操作会触发全集群 controller 重新选举期间元数据变更会短暂阻塞对生产集群来说有风险务必在业务低峰期做并且最好先确认 ZK 集群本身是健康的。至于元数据残留——比如/brokers/topics/foo/partitions/3/state里的 isr 数组包含了早就下线的 broker id或者 leader 指向一个不存在的 broker——这种情况优先交给 controller 自行修复只要把对应 broker 恢复上线controller 处理注册事件时会把状态重写正确。只有当 broker id 被永久移除比如缩容下线时残留信息才需要处理。手工set这个节点是最后手段属于高危操作动手前必须备份 ZK 数据并且要清楚写进去的controller_epoch必须跟当前的 controller epoch 一致否则会被 controller 直接覆盖。3.5 场景五磁盘写满导致的假离线这类故障的迷惑性在于看起来一切正常。broker 进程在、ZK 注册在、监控面板上 CPU 和内存都绿着就是有几个 partition 的 leader 是 -1。排查路径最短df -h看 log.dirs 所在分区。使用率超过 85% 就要警惕接近 100% 时 Kafka 基本上已经在出问题了。原理前面说过写入失败导致 segment 无法正常滚动follower 拉不到新数据被踢出 ISRISR 清零后就是 leader-1。处理分两步。第一步释放空间。如果 topic 设置了retention.hours但清理线程被卡住了可以手工删除明显过期的 segment 目录——注意只删前缀是数字的.log、.index、.timeindex文件不要碰当前正在写的那个也不要删leader-epoch-checkpoint和partition.metadata。判断哪个是当前正在写的看文件名里最大的那个 offset 就是活跃 segment。如果实在分不清宁可先扩容磁盘也不要乱删文件因为索引文件和日志文件不匹配会导致 broker 重启时扫描失败那才是真正的灾难。第二步空间释放后重启 broker 让它重新扫描日志目录等 ISR 恢复。同时把磁盘水位告警阈值调下来80% 预警、85% 处理别等到 95% 才收到通知那时候已经在丢数据了。4. 决定修复成败的几个参数与取舍4.1 unclean.leader.election.enable 该不该开这个参数的历史值得了解一下0.11.0.0 版本之前它默认是true之后改成了false。改动的原因就是太多人因为默认开启而在故障中丢了数据却毫无感知。它的作用机制是允许 controller 从 OSRAR 减去 ISR 的那部分里挑一个副本当 leader。代价是这个副本可能落后原 leader 几个小时甚至几天它一旦上线落后的那部分消息就没有了而且因为 leader_epoch 变了客户端会从新的 offset 开始消费中间那段就这么消失了。我的判断标准是看数据能不能重放。日志、埋点、缓存同步这类数据丢几条无所谓开了能快速恢复服务值得开。订单、支付、账务这类数据丢一条都是事故宁可让 partition 停着等副本恢复也不开。中间地带的比如用户行为数据建议先算清楚丢数据的量级——如果落后量只有几十条开一下问题不大如果落后几十万条那等于把一段时间的业务数据全丢了必须找业务方确认。还有一个容易被忽略的点不要图省事在 broker 级别全局开。broker 级别开意味着所有 topic 都受影响故障时你根本来不及逐个判断。正确姿势是平时保持全局关闭事故时针对具体 topic 开处理完立刻关。4.2 replica.lag.time.max.ms 与 min.insync.replicas 的联动这两个参数决定了 ISR 的收缩和扩张节奏直接影响什么时候会掉到 ISR 为空。replica.lag.time.max.ms默认 30000 毫秒2.5 之前是 10000含义是 follower 超过这个时间没有发起拉取请求、或者拉取进度没有前进就会被踢出 ISR。设得太大慢副本会一直赖在 ISR 里选举时选到它切换后跟不上又得再切一次设得太小网络抖一下、一次 GC 停顿就能把副本踢出去ISR 频繁收缩既增加 controller 负担也让min.insync.replicas更容易被突破。min.insync.replicas配合acksall使用表示至少要有这么多副本确认才算写入成功。3 副本设成 2 是常见配置挂一台还能写。但如果你把这个值设成 3那只要任何一个副本掉出 ISR写入就直接失败报NOT_ENOUGH_REPLICAS。这个组合在故障时会放大问题ISR 一收缩写入就停业务侧看到的就是雪崩。给一组我实际在用的经验配置供参考场景replication.factormin.insync.replicasreplica.lag.time.max.ms说明核心交易数据3230000容忍单副本故障不牺牲一致性普通业务数据3130000可用性优先允许降级写入日志埋点2110000快速剔除慢副本节省资源单机测试1110000无容错能力仅限本地需要说明的是把min.insync.replicas设成 1 意味着只要 leader 活着就能写可用性最高但一致性最弱leader 一挂就可能丢数据。这个取舍必须跟业务方对齐不能由运维单方面拍板。4.3 重分配时的带宽与并发控制前面提到--throttle这里展开讲一下因为它是防止修复引发二次故障的关键。重分配本质上是让新副本从 leader 全量拉数据数据量大的 partition 可能几十上百 GB。如果不限速几个 partition 同时迁移就能把 broker 之间的网络打满导致正常的 follower 拉取也受影响ISR 集体收缩本来只是修一个分区结果引发全集群抖动。--throttle的值按集群规模和业务时段来定。万兆网络、业务低峰期50MB/s 到 100MB/s 都算合理业务高峰期建议压到 10MB/s 以下甚至干脆把重分配安排在凌晨。除了限速还要控制单次重分配的 partition 数量一次别超过几十个分批推进每批 verify 通过再上下一批。老版本还有个坑throttle 不会自动清除。执行完--verify看到全部 completed 之后还需要手工清理限流配置否则这个 broker 会一直被限在那个速率上kafka-configs.sh --bootstrap-server broker1:9092 --alter \ --entity-type brokers --entity-name 1 \ --delete-config leader.replication.throttled.rate,follower.replication.throttled.rate新版本在这方面有改进但不同版本行为不完全一致做完重分配后顺手查一下 broker 的 dynamic config 里还有没有残留的 throttle 项是个好习惯。5. 排查速查表与踩坑记录5.1 常见报错与对应动作速查表故障窗口里最缺的是时间所以我把最常遇到的几类现象整理成一张表遇到时按图索骥能省不少功夫。现象最可能原因关键检查动作处理动作部分 partition leader-1AR 集中在同一台 brokerbroker 宕机或未注册ls /brokers/ids对比集群清单拉起 broker等待自动选举broker 进程在但未注册ZK 会话超时 / 长时间 GC进程存在但/brokers/ids里没有重启 broker排查 GCISR 为空但 AR 中有活副本副本全掉出 ISRkafka-log-dirs.sh确认副本有数据临时开 unclean 选举修完立刻关某副本 size0目录空 / 挂载失败 / 误删kafka-log-dirs.sh --describe优先重分配避免直接删目录leader 迟迟不恢复controller.log 无异常controller 卡在处理队列看 controller 线程栈、GC 日志等待或重启 controller 所在 brokercontroller_epoch 持续增长ZK 不稳 / controller 频繁切换连续get /controller观察先修 ZK再看 controller磁盘使用率接近 100%写入失败导致 ISR 清零df -h、df -i清理过期 segment 或扩容客户端刷 LEADER_NOT_AVAILABLE元数据里没有有效 leaderkafka-topics.sh --describe回到第一层重新排查单副本 topic 重启即 -1replication.factor1查 topic 描述提升副本数重分配重分配后集群整体变慢未限速网络被打满查 broker 网络、ISR 变化加--throttle分批执行5.2 几个我踩过的坑第一个坑是只看--describe不查 ZK。有次看到 leader-1 就想当然认为是 broker 挂了直接重启结果重启完发现 broker 根本没挂只是会话超时被踢出去了重启反而让这台机器上的其他 leader 全部切换了一次影响面扩大了好几倍。从那以后我养成习惯任何动作之前先把ls /brokers/ids和get /controller看一眼确认 controller 眼里的世界跟我想的一致。第二个坑是awk 取错列。kafka-topics.sh --describe的输出格式在不同版本里列数不一样有的版本第一行是 topic 汇总后面每个 partition 一行用 tab 分隔但 tab 的数量会随版本变化。我写过一个脚本按固定列取升级版本后直接失效过滤出来的结果是错的排查方向从一开始就偏了。现在的做法是先| head -5看原始输出确认格式再写过滤逻辑。第三个坑是删目录前没确认 leader 归属。有一次为了快速修复直接在 broker 上rm -rf了一个 partition 目录删完才想起来查这个副本是不是 leader——结果还真是删除瞬间触发了一次 leader 切换而当时集群正好在做其他操作切换失败那个 partition 直接变成 leader-1本来只是修一个坏副本最后变成救一个分区。第四个坑是开了 unclean 忘了关。这个前面提过但值得再强调一次因为它太隐蔽了。topic 级别的配置不会随 broker 重启消失会一直躺在 ZK 的 config 节点里几个月后没人记得故障时就悄悄丢了数据。我的补救办法是把检查所有 topic 的 unclean 配置加进了周巡检脚本发现非 false 的就告警。第五个坑是重分配没限速。一个 200GB 的 partition 全速迁移把两台 broker 之间的链路打满其他 partition 的 follower 拉取超时ISR 集体收缩最后触发了多个 topic 的写入失败。事后复盘时看监控网络曲线是平的顶格非常明显。教训是任何批量操作前先把限速参数写上哪怕是测试环境。5.3 事后巡检与预防故障修完不等于事情结束真正决定下次还会不会出问题的是巡检和预防。我自己维护的一套检查项落地成本不高但很有效。副本分布是第一项。写个脚本把所有 topic 的 AR 拉出来检查是否有 partition 的多个副本落在同一台 broker 上重复 id以及是否跨机架。前者是重分配时的低级错误后者需要broker.rack配置到位。发现重复 id 的用重分配工具重新规划。单副本 topic 是第二项。定期扫一遍replication.factor1的 topic列出清单推给业务方推动它们提升副本数。这类 topic 是定时炸弹平时不响响的时候没人能救。配置漂移是第三项。把unclean.leader.election.enable、min.insync.replicas、replica.lag.time.max.ms这几个关键参数的实际值和预期值对一遍发现偏离就告警。尤其是 topic 级别的覆盖配置很容易在事故处理中被遗忘。磁盘水位和 controller 切换次数是第四项。磁盘 80% 预警controller 切换次数按天统计超过阈值比如一天超过 3 次就要查原因。最后一件事是定期跑 preferred leader 选举。重分配、broker 重启、故障切换之后leader 分布会逐渐偏斜某几台 broker 扛着大部分 leader负载不均。在业务低峰期跑一次全量 preferred 选举kafka-leader-election.sh --bootstrap-server broker1:9092 \ --election-type PREFERRED --all-topic-partitions这个操作是平滑的走的是正常的 leader 切换流程不会丢数据但会带来短暂的元数据变更压力所以别在高峰期做。我个人在实际操作中的体会是leader-1 这个现象本身不可怕可怕的是在信息不全的情况下贸然动手。大部分情况下先花五分钟把broker 状态、副本数据、controller 视图这三样确认清楚修复动作往往只有一条命令反而是急着重启、急着开 unclean、急着删目录的那些次把小故障弄成了大事故。手上有工具心里有分层比什么都重要。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询