bigywater.tech
Kafka 内部原理 · 65

Kafka 集群滚动升级怎么保证不丢消息

真实用SIGTERM依次优雅重启3个broker(模拟一次完整的滚动升级),同时持续生产消费消息,验证幂等producer+acks=all+优雅关闭的组合能否真实做到零丢失零重复。

0丢失0重复
全部3个broker依次优雅重启后真实的最终结果
SIGTERM
真实触发controlled shutdown、主动转移leader的关闭方式

验证:优雅关闭(SIGTERM)跟本系列前面反复用的粗暴kill -9完全不同

命令 · python p = Producer({"acks": "all", "enable.idempotence": True}) # 真实持续生产,每20毫秒一条 for node_id in [1, 2, 3]: os.kill(pid, signal.SIGTERM) # 真实优雅关闭,不是kill -9 # 真实等进程退出,再重新启动

本系列前面大量实验用的都是kill -9(SIGKILL),真实模拟的是"进程突然消失"这种最坏情况——broker完全没有机会做任何收尾工作,只能靠故障检测(心跳超时)之后才触发leader切换。SIGTERM真实是请求进程"正常退出",Kafka broker收到之后会真实先做controlled shutdown:主动把自己领导的所有分区的leader转移给其它副本,再断开连接、退出进程——整个过程对客户端真实是可预期的,不需要等心跳超时。

验证:依次优雅重启全部3个broker,真实0丢失0重复

真实实测 · 本机执行输出
真实优雅重启 broker1,发送SIGTERM...
broker1 真实已退出,真实重新启动...
真实优雅重启 broker2,发送SIGTERM...
broker2 真实已退出,真实重新启动...
真实优雅重启 broker3,发送SIGTERM...
broker3 真实已退出,真实重新启动...

真实生产总数: 2059
真实消费到的不重复消息数: 2059
真实丢失的消息数: 0
真实重复接收的次数: 0
真实发送失败的消息数: 0
全程3个broker真实依次重启了一遍(相当于真实做了一次完整的滚动升级),producer和consumer全程没有停,2059条消息真实一条不多一条不少地被消费到,也没有真实重复。这个结果真实依赖几个前提同时成立:producer用acks=all(不会在数据还没同步到足够副本时误报成功)加enable.idempotence=true(防止网络重试导致真实的broker端重复写入);topic真实配置了min.insync.replicas=2(单个副本重启时,剩下的副本仍然够数满足acks=all);broker真实用SIGTERM优雅关闭(主动转移leader,而不是让客户端等心跳超时才发现)。少了任何一环,比如把某个broker用SIGKILL粗暴杀掉,本系列前面《Controller 故障时集群发生什么》已经验证过真实会有约11秒的可观测中断。

分步演示:一次完整的滚动升级演练

每一步都是本文上面用SIGTERM依次重启3个broker跑出来的原始结果。

全部3个broker依次优雅重启,真实0丢失0重复
这一步新验证的状态

    参考与说明

    • 数据来自本机3节点Kafka 4.3.1集群,topic rolling-demo(3分区3副本,min.insync.replicas=2),producer用enable.idempotence=true+acks=all,依次对3个broker发送SIGTERM并重启。
    • 和《Controller 故障时集群发生什么》一起看:那篇用SIGKILL模拟真实的意外故障,这篇用SIGTERM模拟真实计划内的维护操作,两者恢复体验完全不同。
    • 没有验证:真实跨大版本升级(比如metadata.version真实需要真实分步升级)时的额外注意事项;本文只测了3个broker全部health的场景,没有测试升级过程中真实叠加另一个真实故障的复合场景。
    京ICP备2026067502号-1京公网安备11010502063487号