Redis五-哨兵

目录

哨兵

导读

  1. Redis Sentinel是Redis的高可用实现方案:故障发现、故障自动转移、配置中心、客户端通知
  2. Redis Sentinel从Redis2.8版本开始才正式生产可用,之前版本生产不可用
  3. 尽可能在不同物理机上部署Redis Sentinel所有节点
  4. Redis Sentinel中的Sentinel节点个数应该为大于等于3且最好为奇数
  5. Redis Sentinel中的数据节点与普通数据节点没有区别
  6. 客户端初始化时连接的是Sentinel节点集合,不再是具体的Redis节点,但Sentinel只是配置中心不是代理
  7. Redis Sentinel通过三个定时任务实现了Sentinel节点对于主节点、从节点、其余Sentinel节点的监控
  8. Redis Sentinel在对节点做失败判定时分为主观下线和客观下线
  9. 看懂Redis Sentinel故障转移日志对于Redis Sentnel以及问题排查非常有帮助
  10. Redis Sentinel实现读写分离高可用可以依赖Sentinel节点的消息通知,获取Redis数据节点的状态变化

基本概念

名词 逻辑结构 物理结构
主节点(master) Redis 主服务 / 数据库 一个独立的 Redis 进程
从节点(slave) Redis 从服务 / 数据库 一个独立的 Redis 进程
Redis 数据节点 主节点和从节点 主节点和从节点的进程
Sentinel 节点 监控 Redis 数据节点 一个独立的 Sentinel 进程
Sentinel 节点集合 若干 Sentinel 节点的抽象组合 若干 Sentinel 节点进程
Redis Sentinel Redis 高可用实现方案 Sentinel 节点集合和 Redis 数据节点进程
应用方 泛指一个或多个客户端 一个或者多个客户端进程或者线程

主从复制问题

优点:

作为主节点的一个备份,一旦主节点出了故障不可达的情况,从节点可以作为后备"顶"上来,并且保证数据尽量不丢失(主从复制是最终一致性)

从节点可以扩展主节点的读能力

缺点:

一旦主节点出现故障,需要手动将一个从节点晋升为主节点,同时需要修改应用方的主节点地址,还需要命令其他从节点去复制新的主节点,整个过程都需要人工干预-->Redis高可用问题

主节点的写能力、存储能力受到单机的限制-->Redis分布式问题

Redis Sentinel的高可用性

高可用:

  1. 判断节点不可达的机制
  2. 怎样保证只有一个被晋升为主节点
  3. 通知客户端新的主节点机制是否足够健壮

当主节点出现故障时,Redis Sentinel能自动完成故障发现和故障转移,并通知应用方,从而实现真正的高可用

Redis Sentinel是一个分布式架构,其中包含若干个Sentinel节点和Redis数据节点,每个Sentinel节点会对数据节点和其余Sentinel节点进行监控,

当它发现节点不可达时,会对节点做下线标识。如果被标识的是主节点,它还会和其他Sentinel节点进行"协商"​,

当大多数Sentinel节点都认为主节点不可达时,它们会选举出一个Sentinel节点来完成自动故障转移的工作,同时会将这个变化实时通知给Redis应用方。

1主2从3哨兵

  1. 主节点出现故障,此时两个从节点与主节点失去连接,主从复制失败。
  2. 每个Sentinel节点通过定期监控发现主节点出现了故障
  3. Sentinel节点对主节点的故障达成一致,选举出sentinel-3节点作为领导者负责故障转移
    1. 对其执行slaveof no one命令使其成为新的主节点
    2. 原来的从节点(slave-1)成为新的主节点后,更新应用方的主节点信息,重新启动应用方
    3. 客户端命令另一个从节点(slave-2)去复制新的主节点(new-master)
    4. 待原来的主节点恢复后,让它去复制新的主节点。
  4. Sentinel领导者节点执行了故障转移
    故障>协商>从节点1--slaveof no one--升主>通知client>从节点2复制新的主节点>原来的主节点恢复后复制新的主节点

Redis Sentinel具有以下几个功能:

  1. 监控(Monitoring):Sentinel节点会定期检测Redis数据节点的状态
  2. 通知(Notification):Sentinel节点会将故障转移后的结果通知给应用方
  3. 故障转移(Failover):实现自动的故障转移
  4. 配置中心(Configuration):在Redis Sentinel架构中,客户端连接的是Sentinel节点集合而不是直接连接的Redis数据节点

安装和部署

角色 ip port 别名(为了后文中方便)
master 127.0.0.1 6379 主节点或者 6379 节点
slave - 1 127.0.0.1 6380 slave - 1 节点或者 6380 节点
slave - 2 127.0.0.1 6381 slave - 2 节点或者 6381 节点
sentinel - 1 127.0.0.1 26379 sentinel - 1 节点或者 26379 节点
sentinel - 2 127.0.0.1 26380 sentinel - 2 节点或者 26380 节点
sentinel - 3 127.0.0.1 26381 sentinel - 3 节点或者 26381 节点

部署数据节点

  1. 主节点
bash 复制代码
vi redis-6379.conf

port 6379
daemonize yes
logfile "/var/log/redis-6379.log"
dbfilename "dump-6379.rdb"
dir "/var/redis/data/"
  • daemonize yes # 后台运行
  • logfile "/var/log/redis-6379.log" # 日志文件
  • dbfilename "dump-6379.rdb" # 持久化文件名
  • dir "/var/redis/data/" # 持久化文件存放目录

redis-server redis-6379.conf

  1. 从节点
bash 复制代码
vi redis-6380.conf

port 6380
daemonize yes 
logfile "/var/log/redis-6380.log"  
dbfilename "dump-6380.rdb" 
dir "/var/redis/data/" 
slaveof 127.0.0.1 6379
bash 复制代码
vi redis-6381.conf

port 6381 
daemonize yes 
logfile "/var/log/redis-6381.log"  
dbfilename "dump-6381.rdb" 
dir "/var/redis/data/" 
slaveof 127.0.0.1 6379
  • slaveof 127.0.0.1 6379 # 从节点复制主节点的地址和端口

redis-server redis-6380.conf

redis-server redis-6381.conf

bash 复制代码
redis-cli -p 6379 info replication
# Replication
role:master
connected_slaves:2
slave0:ip=127.0.0.1,port=6380,state=online,offset=491,lag=0
slave1:ip=127.0.0.1,port=6381,state=online,offset=491,lag=1
master_repl_offset:491
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:490

此时拓扑如下:

部署Sentinel节点

bash 复制代码
vi redis-sentinel-26379.conf  # 26379、26380、26381的配置文件类似,只是端口不同

port 26379  
daemonize yes  
logfile "/var/log/26379.log"  
dir /var/redis/data/  
sentinel monitor mymaster 127.0.0.1 6379 2  
sentinel down-after-milliseconds mymaster 30000  
sentinel parallel-syncs mymaster 1  
sentinel failover-timeout mymaster 180000

Sentinel节点的默认端口是26379

sentinel monitor mymaster 127.0.0.1 63792

sentinel-1节点需要监控127.0.0.1:6379这个主节点,

2代表判断主节点失败至少需要2个Sentinel节点同意,

mymaster是主节点的别名

超过了down-after-milliseconds 配置的时间且没有有效的回复,则判定节点不可达
parallel-syncs 就是用来限制在一次故障转移之后,每次向新的主节点发起复制操作的从节点个数

sentinel failover-timeout mymaster 180000 # 故障转移超时时间

sentinel auth-pass mymaster mypassword # 认证密码

sentinel notification-script mymaster /var/redis/notify.sh # 故障通知脚本,当故障转移发生时,会执行这个脚本

sentinel client-reconfig-script mymaster /var/redis/reconfig.sh # 客户端重新配置脚本,当故障转移发生时,会执行这个脚本

启动:

复制代码
redis-sentinel redis-sentinel-26379.conf
redis-server redis-sentinel-26379.conf --sentinel
bash 复制代码
redis-cli -p 26379 info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
master0:name=mymaster,status=ok,address=127.0.0.1:6379,slaves=2,sentinels=3

此时拓扑如下:

Seninel配置优化

Redis安装目录下有一个sentinel.conf,是默认的Sentinel节点配置文件

bash 复制代码
port 26381
daemonize yes
logfile "/var/log/26381.log"
dir "/var/redis/data"
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel config-epoch mymaster 0
sentinel leader-epoch mymaster 0
sentinel known-slave mymaster 127.0.0.1 6380
# Generated by CONFIG REWRITE
sentinel known-slave mymaster 127.0.0.1 6381
sentinel known-sentinel mymaster 127.0.0.1 26380 187ef7cee830e5728fdcf913682f8acc69bca9f6
sentinel known-sentinel mymaster 127.0.0.1 26379 131c66c696c7d604728d2102475dfce8b37d15b2
sentinel current-epoch 0
  • 部署技巧
  1. Sentinel节点不应该部署在一台物理"机器"上
  2. 部署至少三个且奇数个的Sentinel节点

3个以上是通过增加Sentinel节点的个数提高对于故障判定的准确性,因为领导者选举需要至少一半加1个节点,奇数个节点可以在满足该条件的基础上节省一个节点

sentinel API

Sentinel节点是一个特殊的Redis节点,它有自己专属的API

bash 复制代码
sentinel masters  # 查看所有被监控的主节点信息
sentinel master mymaster  # 查看指定主节点的详细信息
sentinel slaves mymaster  # 查看指定主节点的所有从节点信息
sentinel sentinels mymaster  # 查看指定主节点的所有Sentinel节点信息
sentinel get-master-addr-by-name mymaster  # 查看指定主节点的地址和端口
sentinel reset mymaster  # 清除 Sentinel 内部关于 mymaster 的所有状态信息、重新发现并注册 mymaster 的从节点和哨兵节点(通过向主节点发送 ROLE 命令获取拓扑信息)
sentinel failover mymaster  # 手动触发故障转移
sentinel ckquorum mymaster  # 检查 Sentinel 集群是否可以就故障转移达成共识
sentinel flushconfig  # 将Sentinel节点的配置强制刷到磁盘上,通常用于磁盘损坏导致配置丢失
sentinel remove mymaster  # 移除监控的主节点
sentinel monitor mymaster 127.0.0.1 6379 2  # 添加监控的主节点,和配置文件的一致

实现原理

三个定时任务

Redis Sentinel通过三个定时监控任务完成对各个节点发现和监控

  1. 每隔10秒,每个Sentinel节点会向主节点和从节点发送info replication 命令获取最新的拓扑结构-->master、slave
  2. 每隔1秒,每个Sentinel节点会向主节点、从节点以及其他Sentinel节点发送ping命令做一次心跳检测
  3. 每隔2秒,每个Sentinel节点会向Redis数据节点的__sentinel__:hello频道上发送该Sentinel节点对于主节点的判断以及当前Sentinel节点的信息
bash 复制代码
简单的说,就两个作用
1. 了解其他的Sentinel节点信息
2. 了解其他Sentinel节点对于主节点的状态判断


具体细节:
每个 Sentinel 节点既是消息的发布者,也是订阅者。
Sentinel 会向所有已知的数据节点(master 和 slave)发送发布 / 订阅命令

Sentinel 启动时:
向所有已知的 master 和 slave 节点发送 SUBSCRIBE __sentinel__:hello 命令,订阅该频道。
定时任务触发时:
向所有已知的 master 和 slave 节点发送 PUBLISH __sentinel__:hello "消息内容" 命令,发布自身状态和主节点判断。
消息传递逻辑:
无论消息发布到 master 还是 slave,只要节点在线,订阅该频道的其他 Sentinel 都能收到消息(因为 Redis 的 Pub/Sub 是节点级别的,不依赖数据同步)。

主观下线和客观下线

  1. 主观下线

  2. 客观下线

    当Sentinel主观下线的节点是主节点时,该Sentinel节点会通过sentinel is-master-down-by-addr 命令向其他Sentinel节点询问对主节点的判断

    当超过 个数的Sentinel节点认为主节点确实有问题,这时该Sentinel节点会做出客观下线的决定,这样客观下线的含义是比较明显了,也就是大部分Sentinel节点都对主节点的下线做了同意的判定,那么这个判定就是客观的
    例如sentinel-1节点对主节点做主观下线后,会向其余Sentinel节点发送该命令:
    sentinel is-master-down-by-addr 127.0.0.1 6379 0 *

日志分析

先kill掉主节点,然后启动原主节点

bash 复制代码
2793:X 18 Jun 13:39:34.452 # +sdown master mymaster 127.0.0.1 6379  # Sentinel(进程 ID 2793)主观认为 mymaster 主节点(127.0.0.1:6379)下线(不可达)
2793:X 18 Jun 13:39:34.536 # +new-epoch 6  # 开启一个新的选举纪元(Epoch 6)
2793:X 18 Jun 13:39:34.539 # +vote-for-leader 187ef7cee830e5728fdcf913682f8acc69bca9f6 6  # # 当前 Sentinel 投票给节点 187ef7...(另一个 Sentinel)作为领导者
2793:X 18 Jun 13:39:34.539 # +odown master mymaster 127.0.0.1 6379 #quorum 2/2  # Sentinel 集群达成共识,认为 mymaster 客观下线。
2793:X 18 Jun 13:39:34.539 # Next failover delay: I will not start a failover before Wed Jun 18 13:45:34 2025  # 此次故障转移后,6分钟内不会再次发起故障转移
2793:X 18 Jun 13:39:35.616 # +config-update-from sentinel 127.0.0.1:26380 127.0.0.1 26380 @ mymaster 127.0.0.1 6379  # 从 Sentinel 节点 127.0.0.1:26380 接收新的配置信息。
2793:X 18 Jun 13:39:35.616 # +switch-master mymaster 127.0.0.1 6379 127.0.0.1 6381  # 故障转移成功,新主节点切换为 127.0.0.1:6381。
2793:X 18 Jun 13:39:35.616 * +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6381  # 新主节点(6381)开始管理从节点。
2793:X 18 Jun 13:39:35.616 * +slave slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6381  # 新主节点(6381)开始管理从节点。
2793:X 18 Jun 13:40:05.696 # +sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6381  # Sentinel 认为从节点(6379)下线。


2797:X 18 Jun 13:39:34.455 # +sdown master mymaster 127.0.0.1 6379  # +sdown:主观下线
2797:X 18 Jun 13:39:34.532 # +odown master mymaster 127.0.0.1 6379 #quorum 3/2  # +odown:Sentinel 集群达成共识,确认主节点客观下线
2797:X 18 Jun 13:39:34.532 # +new-epoch 6  # +new-epoch 6:开启一个新的选举纪元(Epoch),用于区分不同轮次的故障转移。
2797:X 18 Jun 13:39:34.532 # +try-failover master mymaster 127.0.0.1 6379  # +try-failover:尝试发起故障转移,但不立即执行。需要等待领导者选举完成。
2797:X 18 Jun 13:39:34.533 # +vote-for-leader 187ef7cee830e5728fdcf913682f8acc69bca9f6 6  # +vote-for-leader:投票给领导者
2797:X 18 Jun 13:39:34.538 # 127.0.0.1:26381 voted for 187ef7cee830e5728fdcf913682f8acc69bca9f6 6  # 其他 Sentinel 节点(127.0.0.1:26381 和 26379)也投票给 187ef7...
2797:X 18 Jun 13:39:34.540 # 127.0.0.1:26379 voted for 187ef7cee830e5728fdcf913682f8acc69bca9f6 6  # 其他 Sentinel 节点(127.0.0.1:26381 和 26379)也投票给 187ef7...
2797:X 18 Jun 13:39:34.605 # +elected-leader master mymaster 127.0.0.1 6379  # +elected-leader:获得多数票,当选为故障转移领导者
2797:X 18 Jun 13:39:34.605 # +failover-state-select-slave master mymaster 127.0.0.1 6379  # +failover-state-select-slave:领导者开始选择从节点作为新的主节点候选者。
2797:X 18 Jun 13:39:34.706 # +selected-slave slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379  # +selected-slave:选中从节点 127.0.0.1:6381 作为新主节点。
2797:X 18 Jun 13:39:34.706 * +failover-state-send-slaveof-noone slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379  # +failover-state-send-slaveof-noone:向选中的从节点(6381)发送 SLAVEOF NO ONE 命令,使其成为独立主节点。
2797:X 18 Jun 13:39:34.783 * +failover-state-wait-promotion slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379  # +failover-state-wait-promotion:等待从节点(6381)完成主节点晋升
2797:X 18 Jun 13:39:35.543 # +promoted-slave slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379  # +promoted-slave:从节点(6381)成功晋升为新主节点。
2797:X 18 Jun 13:39:35.543 # +failover-state-reconf-slaves master mymaster 127.0.0.1 6379  # +failover-state-reconf-slaves:开始重新配置其他从节点,使其复制新主节点(6381)。--127.0.0.1 6379:原主节点的 IP 和端口(故障转移后,该节点将作为从节点存在)。
2797:X 18 Jun 13:39:35.614 * +slave-reconf-sent slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379  # +slave-reconf-sent:向从节点(6380)发送 SLAVEOF 命令,使其复制新主节点。
2797:X 18 Jun 13:39:36.622 * +slave-reconf-inprog slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379  # +slave-reconf-inprog:从节点(6380)正在与新主节点(6381)建立复制连接。
2797:X 18 Jun 13:39:36.623 * +slave-reconf-done slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379  # +slave-reconf-done:从节点(6380)完成配置,开始复制新主节点。
2797:X 18 Jun 13:39:36.678 # -odown master mymaster 127.0.0.1 6379  # -odown:取消原主节点(6379)的客观下线状态(但此时它仍是下线的)。
2797:X 18 Jun 13:39:36.678 # +failover-end master mymaster 127.0.0.1 6379  # +failover-end:故障转移流程结束
2797:X 18 Jun 13:39:36.678 # +switch-master mymaster 127.0.0.1 6379 127.0.0.1 6381  # +switch-master:主节点已从 127.0.0.1:6379 切换为 127.0.0.1:6381。
2797:X 18 Jun 13:39:36.679 * +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6381  # +slave:记录新的从节点列表
2797:X 18 Jun 13:39:36.679 * +slave slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6381  # +slave:记录新的从节点列表
2797:X 18 Jun 13:40:06.697 # +sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6381  # +sdown:原主节点(6379)作为从节点暂时不可达。
  1. 故障检测:Sentinel 先主观判断主节点下线(+sdown),后通过法定人数达成客观下线共识(+odown)。
  2. 领导者选举:Sentinel 通过投票选出负责故障转移的领导者(+elected-leader)。
  3. 新主选择与晋升:从从节点中选出最优节点(6381),并将其提升为新主(+promoted-slave)。
  4. 集群重组:通知其他从节点(6380、6379)复制新主(+slave-reconf-done)。
  5. 故障转移完成:更新集群拓扑(+switch-master),恢复服务可用性。
  • 故障转移