Redis 哨兵(Sentinel)通过一套精巧的机制实现了故障检测和故障转移。它通过监控 Redis 主节点和从节点的状态,确保在主节点发生故障时,能够及时检测并执行故障转移,确保系统的高可用性。下面详细探讨 Redis 哨兵如何实现故障检测和转移,并结合代码示例加以说明。
故障检测
Redis 哨兵通过以下步骤实现故障检测:
-
主观下线(Subjective Down, SDOWN):
- 每个哨兵定期(默认每秒)向它监视的每个 Redis 实例(主节点和从节点)发送 PING 命令。如果在指定时间内(由
sentinel down-after-milliseconds
配置项决定)没有收到实例的回复,则该哨兵会将该实例标记为主观下线。
plaintextsentinel down-after-milliseconds mymaster 5000
- 每个哨兵定期(默认每秒)向它监视的每个 Redis 实例(主节点和从节点)发送 PING 命令。如果在指定时间内(由
-
客观下线(Objective Down, ODOWN):
- 当哨兵将某个实例标记为主观下线后,它会与其他哨兵交换信息。如果足够多的哨兵(由
sentinel monitor mymaster
配置项中的 quorum 决定)都认为该实例不可用,则该实例会被标记为客观下线。
plaintextsentinel monitor mymaster 127.0.0.1 6379 2
- 当哨兵将某个实例标记为主观下线后,它会与其他哨兵交换信息。如果足够多的哨兵(由
故障转移
当哨兵系统确定主节点客观下线后,会进行以下步骤实现故障转移:
-
选举领头哨兵:
- 所有参与监控的哨兵会进行一次选举,选举出一个哨兵作为领头哨兵,负责执行故障转移操作。选举基于 Raft 算法。
plaintextsentinel failover-timeout mymaster 60000
-
选择新的主节点:
- 领头哨兵会从现有的从节点中挑选一个作为新的主节点。选择依据包括延迟、同步状态等。
-
提升从节点并重新配置:
- 领头哨兵将选定的从节点提升为新的主节点,同时将其他从节点重新配置为新的主节点的从节点。
plaintextsentinel parallel-syncs mymaster 1
-
通知客户端:
- 哨兵会更新其自己的配置文件,并通知所有 Redis 客户端新的主节点的地址。
plaintextsentinel client-reconfig-script mymaster /path/to/notification/script.sh
配置和代码示例
以下是一个完整的 Redis 哨兵配置示例,展示了如何配置和实现故障检测和转移。
主节点配置 (redis-master.conf
)
plaintext
port 6379
bind 0.0.0.0
dir /var/lib/redis
appendonly yes
启动主节点:
sh
redis-server redis-master.conf
从节点配置 (redis-slave.conf
)
plaintext
port 6380
bind 0.0.0.0
dir /var/lib/redis
appendonly yes
slaveof 127.0.0.1 6379
启动从节点:
sh
redis-server redis-slave.conf
哨兵配置 (sentinel.conf
)
plaintext
port 26379
dir /tmp
# 监控主节点
sentinel monitor mymaster 127.0.0.1 6379 2
# 主节点不可用时间(毫秒)
sentinel down-after-milliseconds mymaster 5000
# 同步从节点的数量
sentinel parallel-syncs mymaster 1
# 故障转移超时时间(毫秒)
sentinel failover-timeout mymaster 60000
# 通知脚本
sentinel client-reconfig-script mymaster /path/to/notification/script.sh
启动哨兵:
sh
redis-sentinel sentinel.conf
Java 客户端示例
使用 Jedis 库连接 Redis 哨兵集群,并进行简单的 Redis 操作。
引入 Jedis 库
在 Maven 项目中添加 Jedis 依赖:
xml
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.6.3</version>
</dependency>
Java 代码示例
以下 Java 代码展示了如何使用 Jedis 库连接和操作带有 Sentinel 的 Redis 集群。
java
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisSentinelPool;
import java.util.HashSet;
import java.util.Set;
public class RedisSentinelExample {
private static final String MASTER_NAME = "mymaster";
public static void main(String[] args) {
// 定义 Sentinel 节点
Set<String> sentinels = new HashSet<>();
sentinels.add("127.0.0.1:26379");
// 创建 JedisSentinelPool 对象
try (JedisSentinelPool sentinelPool = new JedisSentinelPool(MASTER_NAME, sentinels);
Jedis jedis = sentinelPool.getResource()) {
// 执行 Redis 操作
jedis.set("mykey", "myvalue");
String value = jedis.get("mykey");
System.out.println("mykey: " + value);
// 输出连接的主节点信息
System.out.println("Connected to master: " + jedis.getClient().getHost() + ":" + jedis.getClient().getPort());
} catch (Exception e) {
System.err.println("Error: " + e.getMessage());
}
}
}
总结
Redis 哨兵通过主观下线和客观下线机制实现故障检测,并通过领头哨兵选举、提升从节点为新主节点、重新配置从节点以及通知客户端实现故障转移。合理的哨兵配置可以确保 Redis 集群在主节点故障时能够迅速恢复,提高系统的高可用性。