「Kafka 升级」在生产环境是高风险操作:一个 broker 重启期间,它承载的所有分区副本数临时减少,若同时有副本落后或网络抖动,就可能触发 ISR 收缩甚至分区不可用。而「滚动重启」——逐个重启 broker——正是把这种风险分摊到每一步的标准手法,前提是每一步都确认集群恢复健康再走下一步。
本文覆盖从 ZooKeeper 到 KRaft 的迁移、升级前的兼容性检查、滚动重启的正确顺序、版本参数(inter.broker.protocol.version / log.message.format.version)的两阶段升级法,以及监控与回滚——目标是把「升级」从「赌运气」变成「有 checklist 的工程流程」。
1. 两条升级路径
1.1 ZooKeeper 模式(传统)
集群元数据(topic、分区、ISR、ACL)存储在 ZooKeeper
broker 与 ZK 交互,Controller 由 ZK 选举产生
1.2 KRaft 模式(Kafka 3.3+ 生产可用,4.0 移除 ZK)
元数据作为「元数据日志」存在 Kafka 自身(__cluster_metadata topic)
Controller 由 Raft 协议选举,无需 ZK
优点:启动快、元数据扩展性好、运维组件少
1.3 路径选择
| 现状 | 目标 | 路径 |
|---|---|---|
| 旧版 ZK 集群 | 同架构新版 | 原地滚动升级 |
| ZK 集群 | KRaft | 迁移(ZK → KRaft) |
| KRaft 集群 | 新版 KRaft | 原地滚动升级 |
一句话:KRaft 是终局(Kafka 4.0 起移除 ZooKeeper),但迁移有专门流程;同架构升级是相对低风险的滚动重启,跨架构迁移要单独规划。KRaft 架构详见 KRaft 模式 。
2. 升级前检查清单
2.1 兼容性检查
① 目标版本与当前版本的「升级路径」是否直达(避免跨太多大版本)
② 客户端协议版本兼容(老客户端能否连新 broker)
③ 消息格式版本(log.message.format.version)是否需要升级
④ 使用的功能是否被废弃(如 ZK 相关 API、旧版工具)
⑤ 依赖的插件(Connector、Schema Registry)版本兼容
2.2 集群健康基线
# 1. 确认所有分区有完整 ISR
kafka-topics.sh --bootstrap-server kafka:9092 --describe --under-replicated-partitions
# 2. 确认无 offline 分区
kafka-topics.sh --bootstrap-server kafka:9092 --describe --unavailable-partitions
# 3. 确认 controller 健康
zookeeper-shell.sh zk:2181 get /controller # ZK 模式
红线:任何 under-replicated 或 offline 分区未清零前,不得开始升级——带着问题滚动重启 = 雪上加霜。
2.3 容量与流量确认
① 升级窗口选在低峰期(消费 Lag 低、生产流量低)
② 确认磁盘空间充足(升级可能触发日志滚动/重建)
③ 确认无正在执行的大规模重平衡或分区迁移
2.4 备份与回滚预案
① 备份关键配置(server.properties、topic 配置)
② 确认「回滚到旧版本」的步骤可行(消息格式未升级则可回滚)
③ 准备好监控大盘与告警
一句话:升级前最重要的动作是「确认集群健康」——
under-replicated-partitions与unavailable-partitions必须清零;带着不健康的集群滚动重启,等于把风险放大 N 倍。
3. 滚动重启的正确顺序
3.1 核心原则
每次只重启一个 broker
重启后等待:该 broker 的分区 ISR 恢复完整
确认健康后再重启下一个
3.2 单节点重启流程
# ① 重启前:确认该节点分区 ISR 完整
kafka-topics.sh --bootstrap-server kafka:9092 \
--describe --under-replicated-partitions | grep <broker-id>
# ② 优雅停止 broker(发 SIGTERM,让它先卸任 controller / 完成副本同步)
kill -SIGTERM <kafka-pid>
# 等待进程退出,日志出现 "shutdown completed"
# ③ 启动新版本 broker
./bin/kafka-server-start.sh -daemon config/server.properties
# ④ 等待 ISR 恢复:观察该节点的分区重新同步
# 用监控或循环检查 until under-replicated 为空
3.3 优雅关闭 vs 强杀
SIGTERM:broker 优雅关闭——卸任 controller、刷盘、通知其他 broker
SIGKILL:强杀——可能触发更长的恢复、controller 重选
原则:永远用 SIGTERM,给 broker 足够时间优雅退出;controlled.shutdown.enable=true(默认)让 broker 主动迁移 controller 角色。
3.4 controller 重启的特殊性
若重启的是 controller 节点:
→ 触发 controller 选举 → 元数据重新加载 → 短暂元数据操作阻塞
建议:先确认哪些是 controller,必要时先「转移 controller」再重启
# 查看当前 controller
zookeeper-shell.sh zk:2181 get /controller
3.5 自动化滚动脚本骨架
#!/usr/bin/env bash
set -euo pipefail
BROKERS="1 2 3 4 5"
for id in $BROKERS; do
echo ">>> restarting broker $id"
ssh broker-$id "sudo systemctl stop kafka"
# 等待该节点分区 ISR 恢复
until is_isr_healthy "$id"; do sleep 10; done
ssh broker-$id "sudo systemctl start kafka"
# 等待节点上线且 ISR 完整
until is_broker_up "$id" && is_isr_healthy "$id"; do sleep 10; done
echo ">>> broker $id healthy, sleep 60s before next"
sleep 60
done
一句话:滚动重启的黄金法则是**「一次一个 + 每次等 ISR 恢复」**——用
SIGTERM优雅关闭,重启后确认该节点分区重新同步完整,再动下一个。
4. 版本参数的两阶段升级
4.1 三个关键版本参数
inter.broker.protocol.version=3.5 # broker 间通信协议版本
log.message.format.version=3.5 # 消息落盘格式版本
作用:这两个参数让新旧 broker 混合运行成为可能——即使升级了二进制,只要协议/格式版本没升,行为仍兼容旧版。
4.2 两阶段升级法(关键!)
阶段一:升级二进制
① 保持 inter.broker.protocol.version = 旧版本
② 逐个滚动重启所有 broker(新二进制 + 旧协议)
③ 此时集群可随时回滚(回滚 = 换回旧二进制重启)
阶段二:升级协议与格式
④ 全部 broker 就绪后,改 inter.broker.protocol.version = 新版本
⑤ 再滚动重启一次(协议生效)
⑥ 改 log.message.format.version = 新版本
⑦ 再滚动重启(格式生效,此步后不可回滚)
核心价值:阶段一之后、阶段二之前,是回滚的最后窗口——一旦 log.message.format.version 升级,旧版本 broker 将无法读取新格式消息,回滚不再可能。
4.3 参数对照
| 参数 | 含义 | 升级时机 |
|---|---|---|
inter.broker.protocol.version | broker 间通信协议 | 阶段二第 ④ 步 |
log.message.format.version | 消息磁盘格式 | 阶段二第 ⑥ 步(最后) |
log.message.timestamp.type | 时间戳类型 | 需单独确认 |
一句话:两阶段升级法把「二进制升级」与「协议升级」解耦——阶段一只换二进制(可回滚),阶段二才升协议与格式(不可逆);升级前务必确认「回滚窗口」在哪里。
5. 客户端与消息格式
5.1 客户端协议兼容
Kafka 的协议向后兼容:新 broker 能服务旧客户端
但反向不成立:旧 broker 无法服务「使用新特性」的新客户端
策略:先升 broker,再升客户端——broker 先支持新协议,客户端才有升级空间。
5.2 客户端升级注意
① 新版客户端可能默认启用幂等生产者、新分区器 → 行为变化
② 序列化格式(Schema)需向后兼容,别在升级时顺带改 Schema
③ 消费组协议(如 cooperative-sticky)变化可能触发一次全量再平衡
5.3 消息格式版本的影响
# 若升级 log.message.format.version
log.message.format.version=3.5
影响:新写入的消息用新格式
代价:旧 broker 无法读取 → 不可回滚
前提:所有消费者客户端都支持新格式
5.4 升级中的 rebalance 风险
broker 重启 → 消费者感知到分区变化 → 可能触发消费组再平衡
频繁再平衡 → 消费停顿
对策:升级窗口选低峰、确认消费组稳定、避免升级时同时改消费端
一句话:先 broker 后客户端是铁律;
log.message.format.version是不可逆的最后一刀——升级前确认所有消费者都能读新格式。
6. 监控与回滚
6.1 升级期间的监控指标
broker:under-replicated 分区数、offline 分区数、ActiveControllerCount
消费:消费 Lag、消费组再平衡次数
系统:磁盘 IO、网络、GC 暂停
# 关键:升级全程盯着未同步分区
watch -n 5 'kafka-topics.sh --bootstrap-server kafka:9092 \
--describe --under-replicated-partitions | wc -l'
6.2 健康判定标准
可以继续下一步的标志:
- under-replicated-partitions == 0
- unavailable-partitions == 0
- 消费 Lag 回落到基线
- ActiveControllerCount == 1
6.3 回滚预案
| 阶段 | 可否回滚 | 回滚方式 |
|---|---|---|
| 阶段一(仅换二进制) | 可 | 换回旧二进制滚动重启 |
| 阶段二(升协议) | 可 | 改回旧协议版本重启 |
| 升级消息格式后 | 不可 | 只能向前(恢复旧格式需重建) |
6.4 高可用保障
升级期间的分区副本容错依赖 集群高可用设计 ;controller 的选举与故障转移细节见 副本与 Controller 内部机制 。
一句话:升级的安全网是监控——全程盯
under-replicated与offline分区;回滚窗口在消息格式升级之前,之后只能向前。
7. 常见坑
7.1 高频事故清单
| 坑 | 现象 | 对策 |
|---|---|---|
| 带着 under-replicated 升级 | 分区不可用 | 升级前清零 |
| 一次重启多个 broker | ISR 大面积收缩 | 一次一个 |
| SIGKILL 强杀 | 恢复慢、controller 重选 | 用 SIGTERM |
| 直接升消息格式 | 无法回滚 | 两阶段升级 |
| 升级时改 Schema | 消费端解析失败 | Schema 单独演进 |
| 未确认客户端版本 | 老客户端连不上 | 先 broker 后客户端 |
| 忽略 controller 重启 | 元数据操作阻塞 | 先转移 controller |
7.2 升级 checklist
□ 目标版本与升级路径确认
□ 集群健康:under-replicated=0、offline=0
□ 低峰窗口、磁盘充足、无进行中的迁移
□ 备份配置、明确回滚步骤与窗口
□ 两阶段参数策略(协议/格式最后升)
□ 客户端版本兼容确认
□ 监控大盘就绪、告警开启
□ 逐个滚动、每次等 ISR 恢复
□ 升级后验证:收发、消费 Lag、Controller 唯一
7.3 升级后验证
# 端到端收发验证
kafka-console-producer.sh --bootstrap-server kafka:9092 --topic smoke-test <<< "hello"
kafka-console-consumer.sh --bootstrap-server kafka:9092 --topic smoke-test \
--from-beginning --max-messages 1
日常运维监控指标详见 Kafka 监控与运维 。
8. 小结
| 阶段 | 关键动作 | 风险控制 |
|---|---|---|
| 准备 | 健康检查、备份、窗口选择 | 不健康不升级 |
| 阶段一 | 换二进制、滚动重启 | 保留回滚窗口 |
| 阶段二 | 升协议、升格式、再重启 | 格式最后升 |
| 验证 | 收发冒烟、指标回归 | 监控全程 |
| 回滚 | 按阶段判断可行性 | 格式升级前可回 |
一句话记住:Kafka 升级的本质是**「用滚动重启把风险分摊,用版本参数把不可逆推迟」**——一次一个 broker、每次等 ISR 恢复、协议与格式两阶段最后升,全程盯住 under-replicated 与 offline 分区。升级不是一次操作,而是一套有回滚窗口的流程;想清楚「哪一步之后回不去了」,才是安全的升级。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。