# Redis 哨兵模式:主观下线和客观下线 ## 1. 基本概念 ### 哨兵模式(Sentinel) Redis Sentinel 是 Redis 的高可用性解决方案,它主要提供以下功能: - \*\*监控\*\*:持续检查主从服务器是否正常运行() - \*\*通知\*\*:当被监控的 Redis 实例出现问题时,向管理员发送通知 - \*\*自动故障转移\*\*:当主服务器故障时,自动将一个从服务器升级为主服务器 - \*\*配置提供者\*\*:为客户端提供服务发现,告知当前可用的主服务器地址 ## 2. 主观下线 !\[image-20251022202432902\](https://woniumd.oss-cn-hangzhou.aliyuncs.com/daiwei/java/20251022202432959.png) \*\*主观下线\*\*是指\*\*单个 Sentinel 实例\*\*认为某个 Redis 实例已经不可用。 ### 检测机制 - 每个 Sentinel 会定期向所有被监控的 Redis 实例发送 PING 命令 - 如果在配置的 \`down-after-milliseconds\` 时间内没有收到有效回复(PONG) - 该 Sentinel 就会将这个实例标记为"主观下线" \`\`\` # sentinel.conf sentinel monitor mymaster 127.0.0.1 6379 2 # 最后的2表示quorum值 sentinel down-after-milliseconds mymaster 30000 # 30秒无响应则主观下线 \`\`\` 有问题 - \*\*局部判断\*\*:只是一个 Sentinel 的独立判断 - \*\*可能误判\*\*:可能因为网络波动、Sentinel 自身问题导致误判 - \*\*不会触发故障转移\*\*:单纯的主观下线不会立即启动故障转移流程 ## 3.客观下线 \*\*客观下线\*\*是指\*\*多个 Sentinel 实例达成共识\*\*,认为某个 Redis(master) 实例确实不可用。 ### 检测机制 1. 当某个 Sentinel 将主服务器标记为主观下线后 2. 它会向其他 Sentinel 询问他们对这个主服务器的看法 3. 如果\*\*足够数量\*\*的 Sentinel 都报告主服务器主观下线 4. 那么这个主服务器就被标记为"客观下线" \*\*好处:\*\* - \*\*共识判断\*\*:多个 Sentinel 达成一致的判断 - \*\*准确性高\*\*:减少了单点误判的可能性 - \*\*触发故障转移\*\*:客观下线是启动自动故障转移的前提条件 ## 4.脑裂 1、在分布式架构中,因为网络的问题master与所有的slave都失去连接 2、master(老)正常运行 3、slave节点被sentinel选举出一个新的master(新) 4、新、老master同时运行,分别读写自己的数据导致数据不一致 解决方法: 1、把master配置成必须有slave的情况才有效(\*\*\`min-slaves-to-write\`\*\*)\*\*主从复制延迟的最大允许值\*\* \`\`\` min-slaves-to-write 1 最少有多少个slave min-slaves-max-lag 10 主从复制延迟的最大允许值 \`\`\` 2、proxy(中间件) !\[image-20251022202916672\](https://woniumd.oss-cn-hangzhou.aliyuncs.com/daiwei/java/20251022202916723.png) 哨兵模式客户端连接方式 \`\`\` public class RedisClient { private List sentinelAddresses = Arrays.asList( "192.168.1.10:26379", // Sentinel1 "192.168.1.11:26379", // Sentinel2 "192.168.1.12:26379" // Sentinel3 ); public void connect() { // 客户端随机或轮询连接 Sentinel 节点 String currentMaster = queryMasterFromSentinel(sentinelAddresses); connectToRedis(currentMaster); } private String queryMasterFromSentinel(List sentinels) { for (String sentinel : sentinels) { try { // 向 Sentinel 查询当前 Master 地址 String masterAddr = sentinelClient.getMasterAddrByName("mymaster", sentinel); return masterAddr; } catch (Exception e) { // 连接失败,尝试下一个 Sentinel continue; } } throw new RuntimeException("无法从 Sentinel 获取 Master 地址"); } } \`\`\` ## 5.\*\*总结\*\* 1. \*\*主观下线是客观下线的基础\*\*:没有主观下线就没有客观下线 2. \*\*客观下线是故障转移的触发器\*\*:只有客观下线才会启动自动故障转移 3. \*\*Quorum 值的设置很重要\*\*:太小可能导致误判,太大可能导致故障转移不及时 4. \*\*网络分区是主要挑战\*\*:哨兵模式需要处理脑裂等网络分区问题