一、为什么要做滚动升级?

想象一下你正在运营一家24小时营业的便利店,突然说要停业装修,顾客肯定会抱怨。Kafka集群就像这家便利店,滚动升级就是让我们能在不关门的情况下完成"装修"。

传统的停机升级方式就像直接关店装修,所有业务都会中断。而滚动升级则是让集群中的机器一台接一台地轮流升级,就像让店员轮流去休息室换工作服,店里始终有人值班。

举个例子: 假设我们有个3节点的Kafka集群(v2.5.0),要升级到v3.0.0。停机升级的做法是:

  1. 关闭所有节点
  2. 全部升级到v3.0.0
  3. 重启集群

这期间所有消息都无法处理。而滚动升级则是:

  1. 升级节点1并重启
  2. 等节点1恢复后,升级节点2
  3. 最后升级节点3

整个过程业务几乎不受影响。

二、升级前的准备工作

就像搬家前要打包一样,升级前也需要做好充分准备:

  1. 备份数据:这是最重要的保险措施
# 技术栈:Kafka Shell命令
# 备份topic配置
kafka-configs.sh --zookeeper localhost:2181 --entity-type topics --entity-name your_topic --describe > topic_config.backup

# 备份消费者offset(重要!)
kafka-consumer-groups.sh --bootstrap-server localhost:9092 --group your_group --describe > consumer_offsets.backup
  1. 兼容性检查
  • 新旧版本协议兼容性
  • 客户端SDK版本支持情况
  • 新版本是否有破坏性变更
  1. 测试环境验证: 先在测试集群完整演练升级流程,记录每个步骤耗时和可能出现的问题。

三、详细升级步骤详解

让我们用一个实际的例子来说明。假设我们要将3节点的Kafka集群从2.7.0升级到3.1.0:

第一步:逐个升级broker

# 技术栈:Kafka Shell命令
# 1. 停止第一个broker
sudo systemctl stop kafka

# 2. 升级软件包(以Ubuntu为例)
sudo apt-get update
sudo apt-get install kafka=3.1.0

# 3. 修改配置文件(重点调整以下参数)
log.message.format.version=2.7  # 保持旧格式确保兼容
inter.broker.protocol.version=2.7  # 集群内部协议版本

# 4. 启动broker
sudo systemctl start kafka

# 5. 验证节点状态
kafka-broker-api-versions.sh --bootstrap-server broker1:9092

第二步:等待集群稳定

观察以下几个指标是否恢复正常:

  • 分区leader选举完成
  • 副本同步延迟在合理范围
  • 生产消费速率恢复正常

第三步:升级协议版本

当所有broker都升级完成后,需要更新协议版本:

# 技术栈:Kafka Shell命令
# 1. 更新消息格式版本(需要逐个topic执行)
kafka-configs.sh --zookeeper localhost:2181 --entity-type topics --entity-name your_topic --alter --add-config message.format.version=3.1

# 2. 更新集群内部协议版本(在所有broker上修改配置)
inter.broker.protocol.version=3.1
log.message.format.version=3.1

# 3. 滚动重启所有broker使配置生效

四、版本迁移的特殊情况处理

有时候我们需要跨大版本迁移,比如从1.x直接到3.x,这时候需要特别注意:

  1. 中间版本过渡: 某些大版本之间需要先升级到中间版本。比如从0.10.x直接升级到2.0.0,官方建议先升级到1.1.x。

  2. ZooKeeper迁移: Kafka 3.x开始支持不用ZooKeeper的模式(KRaft),如果要迁移:

# 技术栈:Kafka Shell命令
# 1. 以混合模式启动新版本
process.roles=broker,controller
controller.quorum.voters=1@broker1:9093,2@broker2:9093,3@broker3:9093

# 2. 逐步将元数据从ZooKeeper迁移到KRaft
kafka-metadata-shell.sh --snapshot /tmp/kafka/metadata.log
  1. 客户端兼容性: 旧版生产者/消费者可能需要更新代码。建议先升级客户端库,再升级集群。

五、如何确保业务真正无感知

做到以下几点才能称得上"无感知":

  1. 监控关键指标
  • 请求延迟(P99)
  • 吞吐量变化
  • 错误率
  • 副本同步延迟
  1. 客户端重试配置
// 技术栈:Java客户端示例
Properties props = new Properties();
props.put("bootstrap.servers", "broker1:9092,broker2:9092");
props.put("retries", 10); // 足够大的重试次数
props.put("retry.backoff.ms", 1000); // 合理的重试间隔
props.put("max.block.ms", 60000); // 生产阻塞超时时间
  1. 分批升级消费者: 如果消费者数量多,建议分批重启,避免所有消费者同时rebalance导致集群压力过大。

六、升级后的验证工作

升级完成不是终点,还需要验证:

  1. 基础功能测试
# 技术栈:Kafka Shell命令
# 生产测试消息
kafka-console-producer.sh --broker-list localhost:9092 --topic test_topic

# 消费测试消息
kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic test_topic --from-beginning
  1. 性能基准测试: 用kafka-producer-perf-test.sh和kafka-consumer-perf-test.sh工具对比升级前后的性能差异。

  2. 监控观察期: 建议观察24-48小时,特别注意高峰时段的性能表现。

七、常见问题与解决方案

问题1:升级后生产者频繁报错NotEnoughReplicas 解决方案: 检查副本同步状态,适当调整:

min.insync.replicas=2
unclean.leader.election.enable=false

问题2:消费者无法读取某些消息 解决方案: 可能是消息格式不兼容,尝试临时设置:

log.message.format.version=2.7
inter.broker.protocol.version=2.7

问题3:升级后控制器频繁切换 解决方案: 检查网络状况,调整:

controller.socket.timeout.ms=30000
zookeeper.session.timeout.ms=60000

八、技术方案优缺点分析

优点

  1. 业务连续性高,几乎不会中断服务
  2. 可以控制升级节奏,发现问题及时回退
  3. 对客户端透明,无需修改代码

缺点

  1. 升级周期较长(大型集群可能需要数小时)
  2. 需要严格监控确保每个步骤成功
  3. 中间状态复杂,排查问题难度增加

九、经验总结与最佳实践

  1. 小步快跑:尽量保持版本差距不要太大,建议每次只升级一个次要版本
  2. 变更窗口:选择业务低峰期进行升级
  3. 回退方案:提前准备好回退脚本和旧版本安装包
  4. 文档记录:详细记录每个步骤的执行时间和操作人
  5. 监控告警:升级期间加强监控,设置合理的告警阈值

记住,成功的升级=90%的准备+9%的执行+1%的运气。做好充分准备,剩下的就是按部就班执行了。