一、为什么滚动升级会遇到兼容性问题

大家可能都遇到过这样的情况:家里的WiFi路由器需要升级固件,但升级过程中网络会断几分钟。对于Kafka集群来说,滚动升级就像给路由器升级,但更复杂的是,它需要在保证服务不中断的情况下完成。

Kafka集群由多个Broker组成,滚动升级就是一个个节点轮流升级。问题在于,新老版本可能"说不到一块儿去"。比如:

  • 新版本的消息格式老版本看不懂
  • 老版本的API调用新版本不支持
  • 配置参数在新版本中被废弃

这就好比家里换了智能门锁,但你的老钥匙打不开新锁,而新钥匙又插不进老锁孔。

技术栈:Kafka 2.8.0 升级到 3.0.0

二、常见的兼容性问题及解决方案

1. 协议版本不匹配

当第一个Broker升级后,其他节点还在用老版本通信协议时,控制台可能会报这样的错误:

// 错误示例
org.apache.kafka.common.errors.UnsupportedVersionException: 
The broker does not support FETCH requests with version 11

解决方案是在升级前设置协议版本:

# kafka配置示例
inter.broker.protocol.version=2.8  # 保持老版本协议
log.message.format.version=2.8     # 保持老消息格式

2. 客户端兼容性问题

如果你的Java客户端还在用0.10版本,连接新集群时可能会这样:

// 客户端代码示例
Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("key.serializer", StringSerializer.class.getName());
// 老版本API会报错
props.put("partition.assignment.strategy", "range"); 

// 解决方案是升级客户端或使用兼容模式
props.put("api.version.request", "true"); // 启用版本协商

3. ZooKeeper元数据冲突

升级过程中如果ZK节点数据格式变化,可能会出现:

# ZK错误日志示例
ERROR Unexpected exception during persistent node setup (kafka.zookeeper.ZooKeeperClient)
org.apache.zookeeper.KeeperException$UnimplementedException: 

这时需要先升级ZK,或者使用Kafka自带的迁移工具:

# 使用Kafka迁移工具
bin/kafka-metadata-quorum.sh --bootstrap-server localhost:9092 \
    --command-config admin.properties --upgrade --metadata 2.8.0

三、实战升级操作指南

让我们通过一个完整的示例,看看如何安全地进行滚动升级。

1. 升级前准备

首先检查当前集群状态:

# 检查Broker版本
bin/kafka-broker-api-versions.sh --bootstrap-server localhost:9092 | grep software.version

# 检查topic配置
bin/kafka-configs.sh --zookeeper localhost:2181 --entity-type topics --describe

2. 分阶段升级步骤

分三个阶段进行升级:

# 第一阶段:升级协议版本(不重启)
bin/kafka-configs.sh --zookeeper localhost:2181 \
    --entity-type brokers --entity-default \
    --alter --add-config inter.broker.protocol.version=2.8

# 第二阶段:逐个重启Broker
for broker in 1 2 3; do
    ssh broker${broker} "sudo systemctl stop kafka"
    scp kafka_2.13-3.0.0.tgz broker${broker}:~/
    ssh broker${broker} "tar xzf kafka_2.13-3.0.0.tgz"
    ssh broker${broker} "sudo systemctl start kafka"
done

# 第三阶段:最终切换协议版本
bin/kafka-configs.sh --zookeeper localhost:2181 \
    --entity-type brokers --entity-default \
    --alter --add-config inter.broker.protocol.version=3.0

3. 升级后验证

验证集群健康状态:

# 检查所有Broker是否在线
bin/kafka-broker-api-versions.sh --bootstrap-server localhost:9092

# 测试消息生产消费
bin/kafka-console-producer.sh --broker-list localhost:9092 --topic test
bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic test --from-beginning

四、避坑指南与最佳实践

1. 必须遵守的黄金法则

  • 永远先升级测试环境
  • 保持客户端版本与Broker版本同步
  • 在低峰期进行升级操作
  • 准备好回滚方案

2. 版本兼容矩阵参考

这里有个实用的版本对应表:

Kafka版本 兼容客户端版本 推荐ZK版本
2.8.x 2.6.x+ 3.5.x
3.0.x 2.8.x+ 3.6.x
3.2.x 3.0.x+ 3.7.x

3. 监控指标要重点关注

升级过程中要盯着这些指标:

  • UnderReplicatedPartitions:分区复制状态
  • ActiveControllerCount:控制器健康状态
  • RequestHandlerAvgIdlePercent:Broker负载情况

可以用这个命令监控:

bin/kafka-run-class.sh kafka.tools.JmxTool \
    --object-name kafka.server:type=ReplicaManager,name=UnderReplicatedPartitions \
    --jmx-url service:jmx:rmi:///jndi/rmi://localhost:9999/jmxrmi

五、总结与经验分享

经过多次实战升级,我总结了这些血泪教训:

  1. 小版本升级(如2.8.0→2.8.1)通常很安全
  2. 大版本升级(如2.x→3.x)要预留至少4小时窗口期
  3. 生产环境一定要先做数据备份
  4. 使用Kraft模式(去掉ZK依赖)后升级会更简单

最后记住,Kafka就像一辆行驶中的汽车,滚动升级就是边开车边换轮胎。掌握好节奏和技巧,就能平稳到达目的地。