Redis 集群跨大版本升级时,cluster 总线协议可能不兼容,必须采用逐节点替换策略而非直接重启升级,否则会导致槽位丢失或连接震荡。适用场景为 Redis Cluster 跨主版本升级(如 3.2→4.x、6.x→7.x),风险边界是协议不兼容时节点无法握手。
先说结论:Redis 集群跨主版本升级时,若 cluster 总线协议变更,必须走「加新节点—迁槽—下旧节点」的逐替流程,不能直接停旧启新。
- 先确认:用 redis-cli `--cluster` check 检查旧集群无 fail 状态节点和 open slot
- 先处理:按从节点到主节点顺序,逐个替换节点并迁移槽位
- 再验证:执行 CLUSTER NODES 确认新节点状态为 master 且槽位数正确
命令速用版
升级前检查集群状态:
redis-cli `--cluster` check <host>:<port>
查看节点协议兼容性(观察字段顺序、空格分隔符是否一致):
redis-cli -p 6380 CLUSTER NODES
添加新节点到集群:
redis-cli `--cluster` add-node <new-node-ip>:<new-port> <existing-node-ip>:<existing-port>
迁移槽位到新节点:
redis-cli `--cluster` reshard <host>:<port> `--from` <old-node-id> `--to` <new-node-id> `--slots` 16384 `--yes`
下线旧节点:
redis-cli `--cluster` del-node <host>:<port> <old-node-id>
验证同步状态(升级从节点前必须检查):
redis-cli -p 6380 INFO replication | grep -E "(master_repl_offset|slave_repl_offset|master_link_status)"
为什么会这样
Redis 集群跨主版本升级时,cluster 总线协议可能发生变更,导致新旧版本节点无法直接握手通信。Redis 3.2 到 4.x 的 cluster 总线协议不兼容,目的是提供 Redis Cluster 对 Docker/NAT 的兼容性。6.x 与 7.x 的 CLUSTER NODES 格式、故障检测逻辑、ASK/MOVED 响应行为均有差异,强行混跑会触发槽位丢失或连接震荡。某些字段信息特别是和复制相关的字段在不同版本中不一样,日志输出格式也有轻微改变。RDB 文件格式在 4.x 仍可读取 3.2 的 rdb 文件,但反之则不行。
分步处理
步骤 1:升级前准备与兼容性确认
备份当前 Redis 数据包括 RDB 和 AOF 文件,备份 redis.conf 配置文件。阅读新版本的发布说明,重点关注与旧版本的兼容性变化。在测试环境部署新版本进行功能测试和性能测试。执行 redis-cli `--cluster` check 在旧集群上运行,确保无 fail 状态节点和 open slot。
步骤 2:确认版本兼容边界
查询官方文档的 Cluster compatibility 章节。Redis 6.2+ 支持与 7.0 有限共存(仅限数据迁移阶段),但 6.0 与 7.2 无法直连。若当前是 5.0 版本,必须先升到 6.2 再升 7.x。特别注意 redis.conf 中 cluster-require-full-coverage 默认值变化,6.x 为 yes,7.x 为 no,不统一会导致部分节点拒绝服务。
步骤 3:逐节点替换操作
采用「加新、迁槽、下旧」三步闭环。先升级从节点并确认完全同步,master_repl_offset 与 slave_repl_offset 差值必须为 0,且 master_link_status 必须为 up。在新机器启动同配置的新版本 Redis 实例,用 redis-cli `--cluster` add-node 加入集群。执行 reshard 迁移全部槽位,注意`--from` 必须指定原主节点 ID,不能写 IP。等 CLUSTER NODES 显示新节点状态为 master 且槽位数正确、旧节点变为 fail 后,再用 del-node 下线旧节点。
步骤 4:客户端连接层同步切流
升级前检查客户端是否开启 refreshPeriod(Lettuce)或 clusterRefreshInterval(Jedis),建议调小至 500ms。替换节点期间,在应用侧通过 redis-cli -c -p 7001 CLUSTER SLOTS 拿到最新拓扑,对比客户端本地缓存,发现不一致立即触发强制刷新。禁止使用静态 IP 列表初始化连接池,改用「任意一个活跃节点」自动发现模式。
怎么验证是否生效
版本确认:通过 redis-server `--version` 或 redis-cli INFO | grep redis_version 检查 Redis 版本是否升级成功。服务状态检查:使用 sudo systemctl status redis 确认服务是否正常运行,状态应为 active (running)。集群状态验证:执行 redis-cli `--cluster` check 确保所有节点都正常运行并且版本一致。执行 CLUSTER NODES 确认该节点 role 是 master,且其负责的 slot 数量与原主一致。若旧主已下线但仍在节点列表中,要在新主上执行 CLUSTER FORGET 清除残留视图。
常见坑
直接停主节点升级会触发自动故障转移,导致槽位迁移、连接中断、写丢失。很多团队只换服务端,却忽略客户端缓存的老节点地址,Jedis、Lettuce、StackExchange.Redis 均有默认重试机制,但会持续向已下线节点发请求直到超时。禁止在同步未完成时执行 CLUSTER FAILOVER 或 CLUSTER REPLICATE,否则元数据可能混乱。SLAVEOF NO ONE 不等于安全接管,它只是断开复制关系,但不会校验复制缓冲区是否有效、也不会通知集群其他节点。所有节点必须开启 cluster-require-full-coverage no,否则任意一个 slot 不可达就会拒绝全部请求。
常见问题
Redis 3.2 升级到 4.x 可以直接重启节点吗?
不可以。Redis 3.2 到 4.x 的 cluster 总线协议不兼容,必须采用逐节点替换策略,直接重启会导致节点无法握手。
升级从节点后可以直接用 SLAVEOF NO ONE 切主吗?
不可以。SLAVEOF NO ONE 只是断开复制关系,不会通知集群其他节点,应使用 redis-cli -p 6380 cluster failover takeover 命令。
客户端连接池总连不上新主节点是什么原因?
客户端缓存了过期的 slots map。JedisCluster 需调用 refreshClusterNodes(),Lettuce 要调用 redisClient.refreshClusterNodes() 并配置 DynamicNodeResolver。
Redis 6.x 可以直接升级到 7.x 吗?
需先确认版本兼容边界。Redis 6.2+ 支持与 7.0 有限共存,但 6.0 与 7.2 无法直连,若当前是 5.0 必须先升到 6.2 再升 7.x。
参考来源
- wenlongy - 博客园,《redis 3.2 迁移到 4.x 注意事项 和 redis 4.0 的主要特性》
- 《Redis 怎么平滑升级集群版本_采取逐个节点替换策略保障业务无感》
- 《生产环境 Redis 集群如何安全地进行版本升级_采取先升 Slave 再升 Master 的滚动更新策略》
- 《Redis 版本升级要注意什么》
- 《Redis 集群配置有哪些注意事项》
- 《redis 的 cluster 版本升级,具体步骤》