Sentinel(哨兵)是Redis高可用行解决方案:有一个或多个Sentinel实例组成的Sentinel系统可以监视任意多个服务器,以及这些这些祝服务器属下的所有从服务器,并在被监视的主服务器进入下线状态时,自动降下线祝服务器属下的某个从服务器升级为新的主服务器,然后由新的主服务器代替可以下线的主服务器继续处理请求命令。
在虚机上试着部署了sentinels,虚机上面起了三个redis和三个sentinel,Redis的主从关系为
节点信息是: master:127.0.0.1:6379 slave1:127.0.0.1:6380 slave2:127.0.0.1:6381
主sentinel配置信息为
port 26379 sentinel monitor mymaster 127.0.0.1 6379 2
从sentinel-1配置信息为
port 26380 sentinel monitor mymaster 127.0.0.1 6379 2
从sentinel-2配置信息为
port 26381 sentinel monitor mymaster 127.0.0.1 6379 2
然后启动redis服务和sentinel 服务(sentinel服务需要以sentinel方式运行 --sentinel)
root 65695 63216 0 17:26 pts/1 00:00:02 ./src/redis-server 127.0.0.1:6379 root 65702 63252 0 17:26 pts/2 00:00:02 ./src/redis-server 127.0.0.1:6380 root 65709 64405 0 17:26 pts/0 00:00:02 ./src/redis-server 127.0.0.1:6381 root 66232 64582 0 18:10 pts/4 00:00:00 ./src/redis-sentinel *:26379 [sentinel] root 66237 64706 0 18:10 pts/5 00:00:00 ./src/redis-sentinel *:26380 [sentinel] root 66242 64544 0 18:11 pts/3 00:00:00 ./src/redis-sentinel *:26381 [sentinel]
启动之后sentinel日志:
66232:X 03 Aug 2020 18:10:51.793 # Sentinel ID is 8f54d043828da418378992c9b94540471c8deac9 66232:X 03 Aug 2020 18:10:51.793 # +monitor master mymaster 127.0.0.1 6379 quorum 2 66232:X 03 Aug 2020 18:10:51.793 * +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379 66232:X 03 Aug 2020 18:10:51.795 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379 66232:X 03 Aug 2020 18:11:01.232 * +sentinel sentinel 1e80349ee70adf56b3099966a14f27563586e2c3 127.0.0.1 26380 @ mymaster 127.0.0.1 6379 66232:X 03 Aug 2020 18:11:05.566 * +sentinel sentinel 99aea18d93e9f320be483096fe247ff44699bab9 127.0.0.1 26381 @ mymaster 127.0.0.1 6379
可以通过查询当前主节点的信息
./src/redis-cli -h 127.0.0.1 -p 26379 sentinel get-master-addr-by-name mymaster 1) "127.0.0.1" 2) "6379"
然后在主节点模拟执行开销为100*100ms的命令
./src/redis-cli -h 127.0.0.1 -p 6379 DEBUG sleep 100
127.0.0.1:26380节点的日志如下:
66237:X 03 Aug 2020 18:10:59.227 # +monitor master mymaster 127.0.0.1 6379 quorum 2 66237:X 03 Aug 2020 18:14:19.482 # +sdown master mymaster 127.0.0.1 6379 66237:X 03 Aug 2020 18:14:19.553 # +odown master mymaster 127.0.0.1 6379 #quorum 2/2 66237:X 03 Aug 2020 18:14:19.553 # +new-epoch 1 66237:X 03 Aug 2020 18:14:19.553 # +try-failover master mymaster 127.0.0.1 6379 66237:X 03 Aug 2020 18:14:19.555 # +vote-for-leader 1e80349ee70adf56b3099966a14f27563586e2c3 1 66237:X 03 Aug 2020 18:14:19.559 # 8f54d043828da418378992c9b94540471c8deac9 voted for 1e80349ee70adf56b3099966a14f27563586e2c3 1 66237:X 03 Aug 2020 18:14:19.559 # 99aea18d93e9f320be483096fe247ff44699bab9 voted for 1e80349ee70adf56b3099966a14f27563586e2c3 1 66237:X 03 Aug 2020 18:14:19.645 # +elected-leader master mymaster 127.0.0.1 6379 66237:X 03 Aug 2020 18:14:19.645 # +failover-state-select-slave master mymaster 127.0.0.1 6379 66237:X 03 Aug 2020 18:14:19.700 # +selected-slave slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379 66237:X 03 Aug 2020 18:14:19.700 * +failover-state-send-slaveof-noone slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379 66237:X 03 Aug 2020 18:14:19.766 * +failover-state-wait-promotion slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379 66237:X 03 Aug 2020 18:14:20.576 # +promoted-slave slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379 66237:X 03 Aug 2020 18:14:20.576 # +failover-state-reconf-slaves master mymaster 127.0.0.1 6379 66237:X 03 Aug 2020 18:14:20.633 * +slave-reconf-sent slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379 66237:X 03 Aug 2020 18:14:21.596 * +slave-reconf-inprog slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379 66237:X 03 Aug 2020 18:14:21.596 * +slave-reconf-done slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379 66237:X 03 Aug 2020 18:14:21.695 # -odown master mymaster 127.0.0.1 6379 66237:X 03 Aug 2020 18:14:21.695 # +failover-end master mymaster 127.0.0.1 6379 66237:X 03 Aug 2020 18:14:21.695 # +switch-master mymaster 127.0.0.1 6379 127.0.0.1 6380 66237:X 03 Aug 2020 18:14:21.695 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6380 66237:X 03 Aug 2020 18:14:21.695 * +slave slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380 66237:X 03 Aug 2020 18:14:51.707 # +sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380
查询主节点的信息
./src/redis-cli -h 127.0.0.1 -p 26379 sentinel get-master-addr-by-name mymaster 1) "127.0.0.1" 2) "6380"
Redis Sentinel是为Redis提供一个简单的自动化的高可用机制。
Redis Sentinel的目标时通过3个功能来管理Redis:
- 监控Redis的健康状态
- 出现错误后发送通知,例如通知客户端
- 自动创建一个新的master并执行故障转移
例如一主多从的集群里,同时运行着多个sentinel。如果一个sentinel检测到master没响应,那么它会广播一个sdown(自己主观认为的)消息给其他sentinel,当指定数量的sentinel都认为master宕了,那么这就是事实,ODOWN(客观真实的)消息会被广播,之后一个新的master会被选出来。
- 与主服务器建立连接
sentinel启动后,会与配置文件中提供的所有主服务器建立两个连接,一个时命令连接,一个时订阅连接
命令连接用于向服务器发送命令。
订阅连接则是用于订阅服务器的_sentinel_:hello频道,用于获取其他sentinel信息。
- 获取主服务器信息
sentinel会以一定频率向主服务器发送info命令获取信息,包括主服务器自身的信息比如说服务器id,以及对应的从服务器信息,包括ip和port,sentinel会根据info命令的信息更新自己保存的服务器信息,并会与从服务器建立连接
- 获取从服务器信息
与和主服务器的交互相似,sentinel也会以一定的频率通过info命令获取从服务器信息,包括:从服务器id,从服务器与主服务器的连接状态,从服务器的优先级,从服务器的复制偏移等
- 主观下线
sentinel默认会以每秒一次的频率向所有建立连接的服务器(主服务器、从服务器,sentinel服务器)发送ping,如果在down-after-millisecond内都没有收到有效回复,sentinel会将该服务器标记为主观下线,代表该sentinel认为这台服务器已经显现了。
- 客观下线
为了保证服务器真的已经下线了,当sentinel将某个服务器标记为主观下线之后,它会向其他sentinel实例发送sentinel is-master-down-by-addr命令,接收到该命令的sentinel实例会回复主服务器的状态,代表该sentinel对该服务器的连接情况。
- 选举领头的sentinel
当sentinel将一个主服务器标记为客观下线后,监控该服务器的各个sentinel会通过raft算法进行协商,选举一个leader sentinel
选举领头Sentinel的规则和方法
- 所有监控客观下线Master的Sentinel都有可能成为领头Sentinel。
- 每次进行领头Sentinel选举之后,不论是否选举成功,所有Sentinel的配置纪元(configuration epoch)的值都会自动增加一次。
- 在一个配置纪元里面,所有Sentinel都有一次将某个Sentinel设置为局部领头Sentinel的机会,并且局部领头Sentinel一旦设置,在这个配置纪元里面将不能再更改。
- 监视Master客观下线的所有在线Sentinel都有要求其它Sentinel将自己设置为局部领头Sentinel的机会。
- 当一个Sentinel(源Sentinel)向另一个Sentinel(目标Sentinel)发送SENTINEL is-master-down-by-addr命令,并且命令中的runid参数不是“.”符号而是当前Sentinel的运行ID时,这表示当前Sentinel要求目标Sentinel将自己设置为领头Sentinel。
- Sentinel设置局部领头Sentinel的规则是先到先得。即最先向目标Sentinel发送设置要求的Sentinel将会成为局部领头Sentinel,之后接受到的请求都会被拒绝。
- 目标Sentinel接收到SENTINEL is-master-down-by-addr命令后,将向源Sentinel返回一条命令回复,回复中的leader_runid参数和leader_epoch参数分别记录了目标Sentinel的局部领头Sentinel的运行ID和配置纪元。
- 源Sentinel在接收到目标Sentinel返回的命令回复之后,会检查回复中leader_epoch参数的值和自己的配置纪元是否相同,如果相同的话,那么源Sentinel继续取出回复中的leader_runid参数,如果leader_runid参数的值和源Sentinel的运行ID一直,那么表示目标Sentinel将源Sentinel设置成了局部领头Sentinel。
- 如果有某个Sentinel被半数以上的Sentinel设置成了局部领头Sentinel,那么这个Sentinel称为领头Sentinel。
- 领头Sentinel的产生需要半数以上的Sentinel支持,并且每个Sentinel在每个配置纪元里面只能设置一次局部Sentinel,所以在一个配置纪元里面,只会出现一个领头Sentinel。
- 如果在给定时限内,没有一个Sentinel被选举为领头Sentinel,那么各个Sentinel将在一段时间之后再次进行选举,知道选出领头Sentinel为止。
- 故障转移
领头sentinel将会进行故障转移
- 在已下线主服务器的所有从服务器中,挑选一个作为新的主服务器
- 将其他从服务器的主服务器设置成新的
- 将已下线的主服务器的role改为从服务器,并将其主服务器设置成新的,当该服务器重新上线后,就会从一个从服务器的角色继续工作
-
- 挑选新的主服务器的规则
- 过滤掉所有已下线的从服务器
- 过滤掉最近5s没有回复过的sentinel命令的从服务器
- 过滤掉与原主服务器断开事件超过down-after-millseconds*10的从服务器
- 根据从服务器的优先级进行排序,选择优先级最高的那个
- 如果有多个从服务器优先级相同,则选取复制偏移量最大的那个
- 如果上一步的服务器还有很多,则选择id最小的