哨兵模式概述
Redis Sentinel 是 Redis 的高可用性解决方案,它提供了监控、通知、自动故障转移和配置提供者等功能。当主服务器出现故障时,Sentinel 能够自动将某个从服务器升级为新的主服务器,并让其他从服务器改为复制新的主服务器。
哨兵模式架构
📱 Client
应用客户端
↓
🛡️ Sentinel 1
哨兵节点
🛡️ Sentinel 2
哨兵节点
🛡️ Sentinel 3
哨兵节点
↓
🔴 Master
主服务器
🟢 Slave 1
从服务器
🟢 Slave 2
从服务器
特点:自动监控、故障检测、自动故障转移、配置管理
🔧 哨兵配置
配置 Redis Sentinel 的详细步骤:
Redis 服务器配置:
主服务器配置 (redis-master.conf):
# 基本配置 port 6379 bind 0.0.0.0 # 设置密码 requirepass mypassword # 持久化配置 save 900 1 save 300 10 save 60 10000 appendonly yes # 复制配置 repl-backlog-size 1mb repl-backlog-ttl 3600 # 日志配置 logfile "/var/log/redis/redis-master.log" loglevel notice
从服务器配置 (redis-slave.conf):
# 基本配置 port 6379 bind 0.0.0.0 # 指定主服务器 replicaof 192.168.1.100 6379 masterauth mypassword # 从服务器密码 requirepass mypassword # 只读模式 replica-read-only yes # 持久化配置 appendonly yes # 日志配置 logfile "/var/log/redis/redis-slave.log" loglevel notice
Sentinel 配置:
哨兵配置文件 (sentinel.conf):
# 哨兵端口 port 26379 # 绑定地址 bind 0.0.0.0 # 监控主服务器 # sentinel monitorsentinel monitor mymaster 192.168.1.100 6379 2 # 主服务器密码 sentinel auth-pass mymaster mypassword # 故障转移超时时间(毫秒) sentinel down-after-milliseconds mymaster 30000 # 故障转移期间允许的并行同步从服务器数量 sentinel parallel-syncs mymaster 1 # 故障转移超时时间 sentinel failover-timeout mymaster 180000 # 通知脚本(可选) # sentinel notification-script mymaster /var/redis/notify.sh # 客户端重新配置脚本(可选) # sentinel client-reconfig-script mymaster /var/redis/reconfig.sh # 日志配置 logfile "/var/log/redis/sentinel.log" loglevel notice # 工作目录 dir /var/lib/redis # 拒绝危险命令 sentinel deny-scripts-reconfig yes
启动服务:
# 启动 Redis 主服务器 redis-server /etc/redis/redis-master.conf # 启动 Redis 从服务器 redis-server /etc/redis/redis-slave1.conf redis-server /etc/redis/redis-slave2.conf # 启动 Sentinel(至少3个节点) redis-sentinel /etc/redis/sentinel1.conf redis-sentinel /etc/redis/sentinel2.conf redis-sentinel /etc/redis/sentinel3.conf # 或者使用 redis-server 启动 redis-server /etc/redis/sentinel1.conf --sentinel redis-server /etc/redis/sentinel2.conf --sentinel redis-server /etc/redis/sentinel3.conf --sentinel
🔍 哨兵监控
监控哨兵系统的状态和健康度:
监控命令 | 描述 | 示例 |
---|---|---|
SENTINEL masters |
显示所有被监控的主服务器 | redis-cli -p 26379 SENTINEL masters |
SENTINEL slaves <master-name> |
显示指定主服务器的从服务器 | SENTINEL slaves mymaster |
SENTINEL sentinels <master-name> |
显示监控指定主服务器的哨兵 | SENTINEL sentinels mymaster |
SENTINEL get-master-addr-by-name <master-name> |
获取主服务器地址 | SENTINEL get-master-addr-by-name mymaster |
SENTINEL failover <master-name> |
手动触发故障转移 | SENTINEL failover mymaster |
SENTINEL reset <pattern> |
重置哨兵状态 | SENTINEL reset mymaster |
监控脚本示例:
#!/bin/bash # Redis Sentinel 监控脚本 SENTINEL_HOST="127.0.0.1" SENTINEL_PORT="26379" MASTER_NAME="mymaster" LOG_FILE="/var/log/redis-sentinel-monitor.log" # 检查哨兵状态 sentinel_info=$(redis-cli -h $SENTINEL_HOST -p $SENTINEL_PORT INFO sentinel) echo "$(date): Sentinel info: $sentinel_info" >> $LOG_FILE # 获取主服务器信息 master_info=$(redis-cli -h $SENTINEL_HOST -p $SENTINEL_PORT SENTINEL masters) echo "$(date): Master info: $master_info" >> $LOG_FILE # 获取当前主服务器地址 master_addr=$(redis-cli -h $SENTINEL_HOST -p $SENTINEL_PORT SENTINEL get-master-addr-by-name $MASTER_NAME) echo "$(date): Current master: $master_addr" >> $LOG_FILE # 检查从服务器状态 slaves_info=$(redis-cli -h $SENTINEL_HOST -p $SENTINEL_PORT SENTINEL slaves $MASTER_NAME) echo "$(date): Slaves info: $slaves_info" >> $LOG_FILE # 检查哨兵节点 sentinels_info=$(redis-cli -h $SENTINEL_HOST -p $SENTINEL_PORT SENTINEL sentinels $MASTER_NAME) echo "$(date): Sentinels info: $sentinels_info" >> $LOG_FILE
🔄 故障转移流程
Sentinel 自动故障转移的详细流程:
1. 故障检测
主观下线检测
→
2. 客观下线
多数哨兵确认
→
3. 选举领导
选择领导哨兵
→
4. 选择新主
从从服务器中选择
→
5. 故障转移
执行主从切换
→
6. 通知客户端
更新配置信息
故障检测机制:
# 主观下线(Subjectively Down, SDOWN) # 单个哨兵认为主服务器已下线 # 条件:在指定时间内没有收到有效回复 # 客观下线(Objectively Down, ODOWN) # 多个哨兵都认为主服务器已下线 # 条件:达到 quorum 数量的哨兵确认主服务器下线 # 配置示例 sentinel down-after-milliseconds mymaster 30000 # 30秒无响应判定为主观下线 sentinel monitor mymaster 192.168.1.100 6379 2 # 需要2个哨兵确认客观下线
新主服务器选择规则:
💡 选择优先级:
- 排除故障节点:排除已下线、断线的从服务器
- 优先级排序:按
replica-priority
值排序(值越小优先级越高) - 复制偏移量:选择复制偏移量最大的(数据最新)
- 运行ID:如果前面都相同,选择运行ID最小的
故障转移配置:
# 从服务器优先级配置 replica-priority 100 # 值越小优先级越高,0表示永不提升为主服务器 # 故障转移超时配置 sentinel failover-timeout mymaster 180000 # 3分钟 # 并行同步数量 sentinel parallel-syncs mymaster 1 # 故障转移时同时同步的从服务器数量
📱 客户端连接
应用程序如何连接到 Sentinel 管理的 Redis 集群:
Java 客户端示例(Jedis):
import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisSentinelPool; import java.util.HashSet; import java.util.Set; public class SentinelExample { public static void main(String[] args) { // 配置哨兵节点 Setsentinels = new HashSet<>(); sentinels.add("192.168.1.101:26379"); sentinels.add("192.168.1.102:26379"); sentinels.add("192.168.1.103:26379"); // 创建哨兵连接池 JedisSentinelPool sentinelPool = new JedisSentinelPool( "mymaster", // 主服务器名称 sentinels, // 哨兵节点集合 "mypassword" // Redis密码 ); // 使用连接 try (Jedis jedis = sentinelPool.getResource()) { jedis.set("key1", "value1"); String value = jedis.get("key1"); System.out.println("Value: " + value); } // 关闭连接池 sentinelPool.close(); } }
Python 客户端示例(redis-py):
import redis.sentinel # 配置哨兵 sentinel_list = [ ('192.168.1.101', 26379), ('192.168.1.102', 26379), ('192.168.1.103', 26379) ] # 创建哨兵对象 sentinel = redis.sentinel.Sentinel( sentinel_list, socket_timeout=0.1 ) # 获取主服务器连接 master = sentinel.master_for( 'mymaster', socket_timeout=0.1, password='mypassword', decode_responses=True ) # 获取从服务器连接(只读) slave = sentinel.slave_for( 'mymaster', socket_timeout=0.1, password='mypassword', decode_responses=True ) # 使用连接 master.set('key1', 'value1') value = slave.get('key1') print(f'Value: {value}')
Spring Boot 配置:
# application.yml spring: redis: password: mypassword timeout: 2000ms sentinel: master: mymaster nodes: - 192.168.1.101:26379 - 192.168.1.102:26379 - 192.168.1.103:26379 lettuce: pool: max-active: 8 max-idle: 8 min-idle: 0
哨兵模式优缺点
方面 | 优点 | 缺点 |
---|---|---|
高可用性 | 自动故障转移,无需人工干预 | 故障转移有短暂中断 |
监控能力 | 实时监控,及时发现问题 | 需要额外的哨兵节点 |
配置管理 | 自动更新客户端配置 | 配置相对复杂 |
扩展性 | 支持读写分离 | 写能力仍受限于单主 |
一致性 | 保证数据一致性 | 可能有短暂的数据丢失 |
🚨 故障排查
常见问题的诊断和解决方法:
常见问题:
⚠️ 脑裂问题:
现象:网络分区导致出现多个主服务器
解决:配置 min-slaves-to-write
和 min-slaves-max-lag
# 防止脑裂配置 min-slaves-to-write 1 min-slaves-max-lag 10
⚠️ 哨兵无法达成一致:
现象:哨兵节点数量不足或网络问题
解决:确保至少3个哨兵节点,且网络连通
⚠️ 故障转移失败:
现象:主服务器下线但未触发故障转移
排查:检查 quorum 配置、哨兵日志、网络连接
故障排查脚本:
#!/bin/bash # Redis Sentinel 故障排查脚本 SENTINEL_HOSTS=("192.168.1.101" "192.168.1.102" "192.168.1.103") SENTINEL_PORT="26379" MASTER_NAME="mymaster" echo "=== Redis Sentinel 健康检查 ===" # 检查哨兵节点状态 for host in "${SENTINEL_HOSTS[@]}"; do echo "检查哨兵节点: $host:$SENTINEL_PORT" # 检查连接 if redis-cli -h $host -p $SENTINEL_PORT ping > /dev/null 2>&1; then echo "✓ 连接正常" # 检查主服务器信息 master_addr=$(redis-cli -h $host -p $SENTINEL_PORT SENTINEL get-master-addr-by-name $MASTER_NAME 2>/dev/null) if [ $? -eq 0 ]; then echo "✓ 主服务器地址: $master_addr" else echo "✗ 无法获取主服务器地址" fi # 检查哨兵数量 sentinel_count=$(redis-cli -h $host -p $SENTINEL_PORT SENTINEL sentinels $MASTER_NAME | grep -c "name") echo "✓ 哨兵节点数量: $((sentinel_count + 1))" else echo "✗ 连接失败" fi echo "---" done # 检查主服务器状态 echo "检查主服务器状态:" master_info=$(redis-cli -h ${SENTINEL_HOSTS[0]} -p $SENTINEL_PORT SENTINEL get-master-addr-by-name $MASTER_NAME 2>/dev/null) if [ $? -eq 0 ]; then master_host=$(echo $master_info | cut -d' ' -f1) master_port=$(echo $master_info | cut -d' ' -f2) if redis-cli -h $master_host -p $master_port ping > /dev/null 2>&1; then echo "✓ 主服务器 $master_host:$master_port 正常" else echo "✗ 主服务器 $master_host:$master_port 异常" fi else echo "✗ 无法获取主服务器信息" fi
💡 最佳实践:
- 奇数个哨兵:部署奇数个哨兵节点(推荐3个或5个)
- 分布式部署:哨兵节点分布在不同的物理机器上
- 合理配置超时:根据网络环境调整超时参数
- 监控告警:监控哨兵状态,设置告警机制
- 定期演练:定期进行故障转移演练
- 日志分析:定期分析哨兵和Redis日志
- 网络优化:确保哨兵之间网络稳定