2. 集群启动与初始化故障:Broker无法启动、ZooKeeper连接失败、元数据加载异常

集群启动阶段,说白了就是Kafka最脆弱的时刻。我见过太多运维兄弟在凌晨三点盯着Broker日志发呆——明明配置检查了三遍,就是起不来。这一章咱们就聊聊启动时最常见的三类故障,以及我这些年攒下来的排查套路。

核心观点:启动故障80%出在配置不一致、网络不通、或者元数据损坏上。别急着怀疑代码bug,先按流程走一遍。

2.1 Broker无法启动——从日志里找线索

Broker起不来,第一件事不是改配置,是看日志。我习惯先执行这条命令:

tail -200 /var/log/kafka/server.log | grep -iE "ERROR|FATAL|Exception"

常见的错误类型,我整理了一张表:

错误特征 典型日志片段 大概率原因
端口被占用 Address already in use 另一个进程占了9092端口
堆内存不足 OutOfMemoryError: Java heap space JVM参数没调,默认1GB不够
日志目录权限 Permission denied 启动用户无权写log.dirs
配置项非法 Invalid value + 具体配置名 server.properties写错了

端口冲突——这个最好办。我一般用 lsof -i :9092 看看谁占了端口,kill掉或者改Broker的 listeners 配置就行。

堆内存不够——嗯,这里要注意。Kafka默认的堆内存只有1GB,生产环境至少给4-6GB。我见过一个案例,某团队把堆内存设成512MB,结果Broker刚启动就OOM。改 KAFKA_HEAP_OPTS 环境变量就行:

export KAFKA_HEAP_OPTS="-Xms4g -Xmx4g"

日志目录权限——这个坑我踩过。用root启动Kafka,然后切换到普通用户重启,结果日志目录权限不对,Broker直接挂掉。解决方案:确保 log.dirs 目录的属主和启动用户一致。

警告:千万不要用root用户运行Kafka生产集群。安全是一方面,更重要的是权限问题会让你排查到怀疑人生。

2.2 ZooKeeper连接失败——集群的命门

Kafka依赖ZooKeeper做元数据管理和选主。ZK连不上,Broker就卡在初始化阶段。我个人习惯把ZK连接失败分成三类:

  1. 网络不通——防火墙、安全组、DNS解析
  2. ZK集群挂了——ZK本身起不来或者选主失败
  3. 连接参数不对——zookeeper.connect 写错或者超时太短

先看日志里有没有这个:

ERROR [KafkaServer id=1] Fatal error during KafkaServer startup. Prepare to shutdown
org.apache.zookeeper.KeeperException$ConnectionLossException: KeeperErrorCode = ConnectionLoss

看到 ConnectionLoss,别慌。我一般按这个顺序排查:

  • 第一步:从Broker机器上telnet ZK端口。 telnet zk1 2181,通不通?不通就查防火墙。
  • 第二步:检查ZK集群状态。 echo stat | nc zk1 2181,看看Mode是leader还是follower。
  • 第三步:看ZK的 zookeeper.session.timeout.ms。默认6秒,网络抖动大的环境建议调到12-18秒。

小技巧:我曾经遇到一个诡异问题——ZK集群三个节点都活着,但Broker就是连不上。最后发现是ZK的 maxClientCnxns 设成了10,连接数满了。调大这个参数,重启ZK,问题解决。

还有一个常见问题:ZK集群脑裂。ZK用ZAB协议做选主,如果网络分区导致两个节点都认为自己是leader,就会出现脑裂。这时候Kafka会反复重连,Broker日志里全是 ConnectionLoss。解决办法:确保ZK集群有奇数个节点(3、5、7),并且 tickTime 和 initLimit 配置合理。

2.3 元数据加载异常——最头疼的故障

元数据加载异常,说白了就是Broker启动时读不到或者读错了集群的元数据信息。这玩意儿一旦出问题,整个集群可能都起不来。我遇到过最严重的一次,一个生产集群因为元数据损坏,整整宕了4个小时。

元数据加载的流程,我画了张图:

Kafka Broker 元数据加载流程 Broker 启动 连接 ZooKeeper 从 ZK 读取元数据 加载本地日志文件 注册上线完成 常见故障点 ① ZK 连接超时 ② 元数据版本不匹配 ③ 日志文件损坏 ④ 磁盘空间不足 ⑤ 集群ID不一致 ⑥ 分区副本状态异常

元数据加载异常,最常见的几个场景:

2.3.1 集群ID不一致

每个Kafka集群在ZK里有一个唯一的 cluster.id。如果你把两个不同集群的日志目录混在一起,或者手动改了 meta.properties,Broker启动时会报:

ERROR Fatal error during KafkaServer startup. Prepare to shutdown
java.lang.IllegalArgumentException: Cluster ID mismatch: expected xxx, found yyy

解决办法:检查 /tmp/kafka-logs/meta.properties 里的 cluster.id,确保和ZK里的一致。如果不一致,删掉这个文件让Broker重新生成——但前提是你确定日志目录是对的。

警告:删 meta.properties 之前,一定要确认这个Broker属于正确的集群。删错了可能导致数据丢失。

2.3.2 日志文件损坏

Kafka的日志文件是二进制的,如果因为磁盘故障、非正常关机导致文件损坏,Broker加载时会报 CorruptRecordException 或者 InvalidRecordException。我遇到过最惨的一次,一个分区日志文件头损坏,整个Broker启动卡了20分钟。

排查方法:

  • 看日志里具体是哪个分区的文件报错
  • 用 kafka-run-class.sh kafka.tools.DumpLogSegments 工具检查损坏的文件
  • 如果确认是文件损坏,可以尝试用 kafka-replay-log-producer.sh 修复

但说实话,修复工具不一定好用。我个人的建议是:如果损坏的文件不重要(比如是临时数据),直接删掉对应的日志段文件,让Kafka从副本重新同步。如果重要,从备份恢复。

2.3.3 分区副本状态异常

Broker启动时,会从ZK读取每个分区的ISR(In-Sync Replicas)列表。如果某个分区的ISR列表为空,或者副本状态是 OfflineReplica,Broker会卡在元数据加载阶段。

这时候可以用 kafka-topics.sh 查看分区状态:

kafka-topics.sh --bootstrap-server localhost:9092 --describe --topic my-topic

如果看到 Leader: none 或者 Replicas: 1,2,3 Isr: (ISR为空),说明这个分区没有可用的leader。手动触发leader选举:

kafka-leader-election.sh --bootstrap-server localhost:9092 --topic my-topic --partition 0 --election-type preferred

避坑指南:我曾经在生产环境遇到过一个问题——某个Broker重启后,所有分区的ISR都变成了空。查了半天发现是ZK的 max.znode.size 太小,导致元数据写入失败。调大这个参数后,一切恢复正常。

2.4 启动故障的通用排查流程

最后,我总结了一套启动故障的排查流程,你遇到问题可以照着走一遍:

  1. 看日志——server.log 和 controller.log 是重点
  2. 检查网络——Broker之间、Broker和ZK之间
  3. 检查配置——server.properties 和 log4j.properties
  4. 检查磁盘——空间、权限、inode
  5. 检查ZK——集群状态、元数据完整性
  6. 检查元数据——meta.properties、日志文件完整性

嗯,这一章的内容就到这里。启动故障虽然吓人,但只要按流程走,大部分问题都能在10分钟内定位。记住:别慌,先看日志。