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连接失败分成三类:
- 网络不通——防火墙、安全组、DNS解析
- ZK集群挂了——ZK本身起不来或者选主失败
- 连接参数不对——
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个小时。
元数据加载的流程,我画了张图:
元数据加载异常,最常见的几个场景:
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 启动故障的通用排查流程
最后,我总结了一套启动故障的排查流程,你遇到问题可以照着走一遍:
- 看日志——
server.log和controller.log是重点 - 检查网络——Broker之间、Broker和ZK之间
- 检查配置——
server.properties和log4j.properties - 检查磁盘——空间、权限、inode
- 检查ZK——集群状态、元数据完整性
- 检查元数据——
meta.properties、日志文件完整性
嗯,这一章的内容就到这里。启动故障虽然吓人,但只要按流程走,大部分问题都能在10分钟内定位。记住:别慌,先看日志。