一、前言:为什么需要"手动"故障转移?
Redis 分片集群(Cluster)默认支持自动故障转移 ------当主节点宕机时,从节点会自动升主。
但在计划内维护场景 中,我们更希望主动、可控、无损地完成主从切换:
✅ 场景举例:
- 主节点所在服务器需重启或升级
- 主节点CPU/内存持续高负载,需临时切走流量
- 滚动升级 Redis 版本
- 压测前主动切换,避免影响线上主节点
手动故障转移(Manual Failover) 正是为此设计:无需停机、数据零丢失、业务无感知!
本文将手把手教你如何安全执行手动切换。
二、手动故障转移 vs 自动故障转移
| 对比项 | 自动故障转移 | 手动故障转移 |
|---|---|---|
| 触发条件 | 主节点宕机/失联 | 运维人员主动触发 |
| 切换速度 | 15~30 秒(依赖超时) | 秒级完成 |
| 数据一致性 | 可能丢失最后几秒写入 | 完全同步,零数据丢失 |
| 业务影响 | 短暂不可用 | 几乎无感 |
| 适用场景 | 故障应急 | 计划内维护、升级、优化 |
✅ 核心优势 :在主从数据完全同步的前提下切换,确保强一致性!
三、原理:如何实现"无损"切换?
手动故障转移通过以下机制保证安全:
- 从节点向主节点发起 SYNC 请求
- 确保所有复制偏移量(replication offset)已追平
- 主节点暂停客户端写入(可选)
- 通过
CLUSTER FAILOVER TAKEOVER可跳过此步(强制切换)
- 通过
- 从节点升主,主节点降从
- 角色互换,IP 不变(客户端连接不受影响)
🔑 关键命令 :
CLUSTER FAILOVER [FORCE|TAKEOVER]
四、实战步骤:安全执行手动故障转移
4.1 环境说明
- 主节点:
192.168.1.10:7001 - 从节点:
192.168.1.10:7004(主 7001 的从)
4.2 步骤 1:确认主从同步状态
bash
# 在从节点执行
redis-cli -p 7004 INFO REPLICATION
关注输出:
master_host:192.168.1.10
master_port:7001
master_link_status:up # 必须为 up
master_last_io_seconds_ago:0 # 最近一次通信(越小越好)
slave_read_only:1
✅ 确保 master_link_status: up 且 lag 很小(< 1s)
4.3 步骤 2:在从节点触发手动故障转移
bash
# 登录从节点(7004),执行:
redis-cli -p 7004 CLUSTER FAILOVER
⏱️ 等待 1~3 秒,命令会阻塞直到切换完成。
可选参数说明:
| 命令 | 作用 |
|---|---|
CLUSTER FAILOVER |
标准模式:等待数据完全同步后切换(推荐) |
CLUSTER FAILOVER FORCE |
强制模式:不等待同步,立即切换(可能丢数据) |
CLUSTER FAILOVER TAKEOVER |
接管模式:无需主节点参与(主已宕机时使用) |
💡 生产建议 :始终使用无参
CLUSTER FAILOVER,确保数据安全。
4.4 步骤 3:验证角色是否互换
查看新主(原从 7004):
bash
redis-cli -p 7004 ROLE
# 返回:1) "master" 2) (integer) 12345 ...
查看新从(原主 7001):
bash
redis-cli -p 7001 ROLE
# 返回:1) "slave" 2) "192.168.1.10" 3) (integer) 7004 ...
查看集群拓扑:
bash
redis-cli -p 7004 CLUSTER NODES
# 应显示 7004 为 master,7001 为 slave
✅ 角色已成功互换!
4.5 步骤 4:验证业务读写正常
bash
# 写入新主(7004)
redis-cli -c -p 7004 SET manual_failover_test "success"
# 读取(任意节点)
redis-cli -c -p 7001 GET manual_failover_test # 返回 "success"
✅ 客户端无需修改连接地址!因为 slot 归属未变,只是主从角色互换。
五、高级场景:主节点已宕机,如何强制接管?
若主节点已无法响应 (如服务器宕机),但你想立即升从为主:
在从节点执行:
bash
redis-cli -p 7004 CLUSTER FAILOVER TAKEOVER
⚠️ 注意:
- 此操作绕过集群共识,仅在紧急情况下使用
- 可能导致脑裂(若原主恢复但未降级)
- 操作后需手动清理原主 (重启后执行
CLUSTER RESET SOFT)
六、客户端影响分析
6.1 连接是否中断?
-
TCP 连接本身不断开(IP:Port 未变)
-
但原主降从后变为 read-only ,写请求会报错:
(error) READONLY You can't write against a read only replica.
6.2 如何做到"业务无感"?
现代客户端(如 Lettuce)会:
- 捕获
READONLY错误 - 主动刷新集群拓扑
- 重试写请求到新主
✅ 效果 :应用层可能收到一次异常,但重试后即可成功。
6.3 Spring Boot 优化建议
java
// 配置重试机制(结合 Resilience4j 或 Spring Retry)
@Retryable(value = {RedisCommandExecutionException.class}, maxAttempts = 3, backoff = @Backoff(delay = 100))
public void setValue(String key, String value) {
redisTemplate.opsForValue().set(key, value);
}
七、生产环境最佳实践
✅ 必须遵守
- 切换前检查主从延迟 (
INFO REPLICATION) - 避开业务高峰期
- 每次只切换一个分片(避免多点故障)
- 切换后验证数据一致性(抽样比对)
✅ 推荐流程(维护 checklist)
html
- [ ] 确认主从同步状态正常
- [ ] 通知相关团队(可选)
- [ ] 执行 `CLUSTER FAILOVER`
- [ ] 验证新主可写、新从可读
- [ ] 监控 QPS/延迟/错误率 5 分钟
- [ ] 记录操作日志
八、常见问题排查
❌ 问题 1:CLUSTER FAILOVER 卡住不动
- 原因:主从数据未同步完成
- 解决:等待或检查网络/主节点负载
❌ 问题 2:切换后客户端持续报 MOVED
- 原因:客户端未刷新拓扑
- 解决 :Lettuce 配置
enablePeriodicRefresh
❌ 问题 3:原主恢复后未自动降从
- 原因:原主配置未更新
- 解决 :重启原主,或手动执行
REPLICAOF <new-master>
九、结语
感谢您的阅读!如果你有任何疑问或想要分享的经验,请在评论区留言交流!