Redis篇(十三):Sentinel 故障转移、脑裂问题与 RedLock

发布时间:2026/6/19 1:26:58
Redis篇(十三):Sentinel 故障转移、脑裂问题与 RedLock 一、Sentinel 故障转移全流程Redis Sentinel 是 Redis 的高可用解决方案负责监控主从节点、自动故障转移、通知客户端。1.1 故障检测主观下线与客观下线主观下线SDOWNSentinel 每 1 秒向主从节点发送 PING 命令 ↓ 节点超时未响应默认 down-after-milliseconds: 5000ms ↓ 单个 Sentinel 标记为「主观下线」客观下线ODOWNSentinel 向其他 Sentinel 发送 SENTINEL is-master-down-by-addr 询问 ↓ 多数 Sentinel 同意该节点已下线 ↓ 标记为「客观下线」触发故障转移1.2 Leader 选举Raft 共识算法Sentinel 集群中需要选举一个 Leader 来执行故障转移发现客观下线的 Sentinel 成为候选者 ↓ 候选者向其他 Sentinel 发送拉票请求 ↓ 每个 Sentinel 只有一票可投给自己或他人 ↓ 获得半数以上票数 → 成为 LeaderRaft 算法核心候选者Candidate发现客观下线的 Sentinel 发起选举投票Vote每个 Sentinel 只能投一票先到先得任期Term每次选举递增任期号防止旧 Leader 干扰1.3 新主节点选择Leader 从从节点中选择新主进行三轮考察轮次考察维度规则第一轮断开时间与主节点断开时间最短数据最新第二轮复制偏移量replication offset 最大数据最全第三轮优先级replica-priority 最高0 表示不参与第四轮Run IDID 最小打破平局1.4 故障转移执行① 新主节点晋升 ↓ ② 向其他从节点发送 SLAVEOF new_master 命令 ↓ ③ 向 switch-master 频道发布新主信息 ↓ ④ 客户端订阅该频道自动切换到新主 ↓ ⑤ 旧主节点重新上线后Sentinel 发送 SLAVEOF 降级为从1.5 Sentinel 典型架构3 个 Sentinel 节点 1 主 2 从最小高可用配置 Sentinel 节点数应为奇数至少 3 个避免脑裂二、脑裂问题成因、影响与解决方案2.1 什么是脑裂脑裂场景主节点与所有从节点网络断开 ↓ 但主节点与客户端网络正常 ↓ 客户端继续向旧主写入数据 ↓ Sentinel 发现主节点失联选举新主 ↓ 集群出现两个主节点旧主 新主 ↓ 网络恢复后旧主被降级为从数据清空 ↓ 脑裂期间写入的数据全部丢失2.2 脑裂的影响影响说明数据丢失旧主被降级后脑裂期间的数据全部清空数据不一致客户端可能读到旧数据或新数据业务异常基于旧数据的业务决策可能错误2.3 解决方案方案一min-slaves 限制推荐# redis.conf# 当从节点数量少于 2 个或复制延迟超过 10 秒时主节点拒绝写请求min-slaves-to-write2min-slaves-max-lag10原理脑裂发生时旧主与从节点失联从节点数量变为 0触发 min-slaves-to-write 限制旧主拒绝写请求客户端收到错误可将数据写入本地缓存或消息队列新主上线后数据写入新主避免丢失方案二客户端降级处理// 主节点不可写时降级到本地缓存publicvoidwriteData(Stringkey,Stringvalue){try{redisTemplate.opsForValue().set(key,value);}catch(RedisCommandExecutionExceptione){// 主节点拒绝写入降级到本地缓存localCache.put(key,value);// 异步同步到消息队列mqProducer.send(newCacheSyncMessage(key,value));}}三、RedLock多独立 Redis 实例实现分布式锁3.1 为什么需要 RedLock在单机 Redis 中分布式锁通过SET key value NX PX ttl即可实现。但在集群模式下如果主节点宕机从节点晋升为主节点由于主从复制是异步的锁数据可能丢失导致多个客户端同时获取到锁。RedLock红锁是 Redis 作者 Antirez 提出的分布式锁算法基于多个独立的 Redis 实例构建分布式锁即使部分实例故障锁数据依然可靠。3.2 RedLock 核心设计关键要求N 个完全独立、隔离的 Redis 实例非 Cluster 节点官方推荐至少 5 个奇数个节点之间没有任何关系不同集群或单例部署⚠关键注意Redis Cluster 节点不能用于 RedLock因为 Cluster 节点不独立、不隔离。3.3 RedLock 加锁流程① 获取当前时间 t1毫秒级时间戳 ↓ ② 依次向 N 个独立 Redis 实例发送 SET key value NX PX ttl ↓ ③ 每个实例设置加锁超时时间远小于锁过期时间如 10ms ↓ ④ 统计成功加锁的实例数获取当前时间 t2 ↓ ⑤ 成功条件成功实例数 ≥ N/21 且 (t2-t1) 锁过期时间 ↓ ⑥ 若成功锁实际有效时间 过期时间 - (t2 - t1) - 时钟漂移补偿 ↓ ⑦ 若失败向所有实例发送解锁脚本Lua DEL3.4 RedLock 解锁流程① 向所有 N 个 Redis 实例发送解锁请求 ↓ ② 使用 Lua 脚本保证原子性 if redis.call(get, KEYS[1]) ARGV[1] then return redis.call(del, KEYS[1]) else return 0 end ↓ ③ 即使部分实例解锁失败锁最终也会因 TTL 过期而释放3.5 Java 实现RedissonConfigconfignewConfig();config.useRedLock().addNodeAddress(redis://192.168.0.1:7000).addNodeAddress(redis://192.168.0.2:7000).addNodeAddress(redis://192.168.0.3:7000).addNodeAddress(redis://192.168.0.4:7000).addNodeAddress(redis://192.168.0.5:7000);RedissonRedLockredLockRedisson.create(config).getRedLock(myLock);try{booleanlockedredLock.tryLock(10,30,TimeUnit.SECONDS);if(locked){// 执行业务逻辑}}finally{redLock.unlock();}3.6 RedLock 的争议RedLock 算法在社区中存在争议Martin Kleppmann 的批评争议点说明时钟依赖如果节点时钟发生跳跃可能导致锁失效网络延迟网络分区可能导致多个客户端同时认为获取锁成功实现复杂需要维护多个独立 Redis 实例运维成本高替代方案金融级场景可考虑 Zookeeper / Etcd实际应用建议大多数业务场景中Redisson 的单机锁 看门狗已足够金融级强一致性场景建议使用 Zookeeper 或 EtcdRedLock 适合对可用性要求极高、可容忍轻微不一致的场景如果本文对你有帮助欢迎点赞 收藏 ⭐ 关注 你的支持是我持续创作的动力