Redis实战(七)哨兵机制(Sentinel)

18
High availability for non-clustered Redis.

哨兵机制和主从复制配合来实现高可用架构,而集群是对两者的集成,兼具主从复制和master节点高可用。

是什么?

哨兵巡查监控后台master主机是否故障,如果故障了根据投票数自动将某一个slave转换为新master,继续对外服务。

能干嘛?

  • 主从监控:监控主从redis是否运行正常
  • 消息通知:哨兵可以将故障转移的结果发送给客户端
  • 故障转移:如果master异常,则会进行主从切换,将其中一个slave作为新master
  • 配置中心:客户端通过连接哨兵来获得当前redis服务的主节点地址

怎么玩?

哨兵一般配置奇数个(方便投票),配置3台足矣。
哨兵和redis-server不共享配置文件,有其他配置方式。哨兵配置文件默认在源码包根目录下,文件名为sentinel.conf

哨兵主要的配置参数:

  • sentinel monitor <master-name> <ip> <redis-port> <quorum>:quorum表示客观下线的最少投票数。换句话说,只有当quorum个以上的sentinel连接不上该master后,才会认为该master已经下线
  • sentinel auth-pass <master-name> <password>:配置master的鉴权密码,master如果配置了requirepass,则这里也需要告知sentinel

其他配置参数

  • sentinel down-after-milliseconds <master-name> <milliseconds>:指定多少毫秒之后,主节点没有应答哨兵,此时哨兵主观认为主节点下线
  • sentinel parallel-syncs <master-name> <nums>:表示允许并行同步的slave个数,当master挂了后,哨兵会选择新的master,此时,剩余的slave会向新的master发起同步数据请求
  • sentinel failover-timeout <master-name> <milliseconds>:故障转移的超时时间,进行故障转移时,如果超过设置的毫秒,表示故障转移失败
  • sentinel notification-script <master-name> <script-path>:配置当某一事件发生时所需要执行的脚本
  • sentinel client-reconfig-script <master-name> <script-path>:客户端重新配置主节点参数脚本

哨兵的最小配置项

# 配置端口
port 26379
# 任何地址都可以连接
bind 0.0.0.0
# 以守护模式运行
daemonize yes
# 关闭保护模式
protected-mode no
logfile "/data/redis/logs/sentinel-26379.log"
pidfile "/var/run/redis-sentinel-26379.pid"
# 配置数据存放牡蛎
dir /data/redis
# 配置主节点
sentinel monitor mymaster 127.0.0.1 6379 2
# 配置主节点的鉴权密码
sentinel auth-pass mymaster 123456

哨兵可以监控多个master,可以根据mastername进行区分。

通过配置文件启动哨兵
redis-sentinel /etc/redis/sentinel.conf或者redis-server /etc/redis/sentinel.conf --sentinel

sentinel配置重写
哨兵在启动后,会将master、slave和其他哨兵的信息写入配置文件,方便宕机后的重启。重写的配置信息示例如下:

...
# Generated by CONFIG REWRITE
latency-tracking-info-percentiles 50 99 99.9
user default on nopass sanitize-payload ~* &* +@all
sentinel myid d6d2cc05ee0ba0a51b8e292fe1006c068bb63ced
sentinel config-epoch mymaster 2 
sentinel leader-epoch mymaster 2
sentinel current-epoch 2
sentinel known-replica mymaster 127.0.0.1 6379 
sentinel known-sentinel mymaster 127.0.0.1 26381 44c8309c4d52025c892423728de2aac0d67d505b                   
sentinel known-sentinel mymaster 127.0.0.1 26380 815cd05b9eeb72f69700b6ab12cbcc4f4b7cdf6c                   
sentinel known-replica mymaster 127.0.0.1 6381

redis-server配置重写
前面有提到,哨兵其中一个功能是配置中心,在运行过程中,它可以将redis-server的启动配置进行重写,添加了一些配置项,如果slave变为master,它也会注释掉一些只有slave可以配置的配置项(如replicaof)。下面是主节点宕机重启后重写的配置:

# Generated by CONFIG REWRITE
# 从6380处同步数据
replicaof 127.0.0.1 6380
latency-tracking-info-percentiles 50 99 99.9
user default on sanitize-payload #e2a50c5ade01e4c93ca1b68e42bdb884db26dfd6c745ff01ad44433fdc25425b ~* &* +@all

文件的内容在运行期间会被sentinel动态进行修改。master-slave切换后,master_redis.conf、slave_redis.conf和sentinel.conf的内容都会发生改变,即master_redis.conf会多一行slaveof的配置,sentinel.conf的监控目标也会随之调换。

选举新master日志追踪
在sentinel配置的日志文件中详细记录了master选举的过程和各redis服务的上下线情况,示例如下:

2803888:X 13 Oct 2023 17:21:32.638 * oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
2803888:X 13 Oct 2023 17:21:32.638 * Redis version=7.2.0, bits=64, commit=00000000, modified=0, pid=2803888, just started
2803888:X 13 Oct 2023 17:21:32.638 * Configuration loaded
2803888:X 13 Oct 2023 17:21:32.640 * monotonic clock: POSIX clock_gettime
2803888:X 13 Oct 2023 17:21:32.640 * Running mode=sentinel, port=26379.
2803888:X 13 Oct 2023 17:21:32.642 * Sentinel ID is d6d2cc05ee0ba0a51b8e292fe1006c068bb63ced
2803888:X 13 Oct 2023 17:21:32.642 # +monitor master mymaster 127.0.0.1 6379 quorum 2
2803888:X 13 Oct 2023 17:23:03.323 # +sdown slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379
2803888:X 13 Oct 2023 17:23:17.392 # +sdown master mymaster 127.0.0.1 6379
2803888:X 13 Oct 2023 17:23:17.464 # +odown master mymaster 127.0.0.1 6379 #quorum 3/2
2803888:X 13 Oct 2023 17:23:17.465 # +new-epoch 1
2803888:X 13 Oct 2023 17:23:17.465 # +try-failover master mymaster 127.0.0.1 6379
2803888:X 13 Oct 2023 17:23:17.474 * Sentinel new configuration saved on disk
2803888:X 13 Oct 2023 17:23:17.475 # +vote-for-leader d6d2cc05ee0ba0a51b8e292fe1006c068bb63ced 1
2803888:X 13 Oct 2023 17:23:17.475 * 815cd05b9eeb72f69700b6ab12cbcc4f4b7cdf6c voted for 815cd05b9eeb72f69700b6ab12cbcc4f4b7cdf6c 1
2803888:X 13 Oct 2023 17:23:17.485 * 44c8309c4d52025c892423728de2aac0d67d505b voted for 815cd05b9eeb72f69700b6ab12cbcc4f4b7cdf6c 1
2803888:X 13 Oct 2023 17:23:27.964 # -failover-abort-not-elected master mymaster 127.0.0.1 6379
2803888:X 13 Oct 2023 17:23:28.030 * Next failover delay: I will not start a failover before Fri Oct 13 17:29:17 2023
2803888:X 13 Oct 2023 17:26:04.195 * +reboot master mymaster 127.0.0.1 6379
2803888:X 13 Oct 2023 17:26:04.272 # -sdown master mymaster 127.0.0.1 6379
2803888:X 13 Oct 2023 17:26:04.272 # -odown master mymaster 127.0.0.1 6379
2803888:X 13 Oct 2023 17:26:08.365 * +reboot slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379
2803888:X 13 Oct 2023 17:26:08.456 # -sdown slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379
2803888:X 13 Oct 2023 17:26:14.251 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379
2803888:X 13 Oct 2023 17:26:14.258 * Sentinel new configuration saved on disk
2803888:X 13 Oct 2023 17:27:45.489 # +sdown master mymaster 127.0.0.1 6379
2803888:X 13 Oct 2023 17:27:45.560 # +odown master mymaster 127.0.0.1 6379 #quorum 3/2
2803888:X 13 Oct 2023 17:29:17.809 * Sentinel new configuration saved on disk
2803888:X 13 Oct 2023 17:29:17.809 # +new-epoch 2
2803888:X 13 Oct 2023 17:29:17.817 * Sentinel new configuration saved on disk
2803888:X 13 Oct 2023 17:29:17.818 # +vote-for-leader 815cd05b9eeb72f69700b6ab12cbcc4f4b7cdf6c 2
2803888:X 13 Oct 2023 17:29:17.849 * Next failover delay: I will not start a failover before Fri Oct 13 17:35:17 2023
2803888:X 13 Oct 2023 17:29:18.817 # +config-update-from sentinel 815cd05b9eeb72f69700b6ab12cbcc4f4b7cdf6c 127.0.0.1 26380 @ mymaster 127.0.0.1 6379
2803888:X 13 Oct 2023 17:29:18.817 # +switch-master mymaster 127.0.0.1 6379 127.0.0.1 6380
2803888:X 13 Oct 2023 17:29:18.817 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6380
2803888:X 13 Oct 2023 17:29:18.817 * +slave slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380
2803888:X 13 Oct 2023 17:29:18.829 * Sentinel new configuration saved on disk
2803888:X 13 Oct 2023 17:29:48.882 # +sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380
2803888:X 13 Oct 2023 17:31:06.000 # -sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380
2803888:X 13 Oct 2023 17:35:46.092 * +reboot slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380

注意事项
master宕机后,重启后连接不上sentinel新选举的master
这是由于对sentinel新选举的redis配置了密码,而原master中并未配置masterauth字段。如果需要使用sentinel+主从复制来实现redis的高可用,那么就需要在所有的redis服务中都配置masterauth配置项,因为所有的redis都有可能成为新的master

哨兵运行流程和选举原理

当master宕机后,单个哨兵通过心跳检测发现master不可用,然后将该消息发送给其他哨兵,如果有超过quorum数量的sentinel认为master不可用后,将会开启一轮选举流程,新的master将产生,哨兵将修改新master、所有slave的配置以及哨兵的配置,所有slave将连接到新的master上,然后master开始同步数据。

主观下线(SDOWN, subjectively down)
哨兵通过心跳检测(ping)发现自己丢失了与master的连接,这时候该哨兵认为master已不可用(主观)

  • sentinel down-after-milliseconds <master-name> <milliseconds>可以配置sentinel认为多长时间无回复,即可认为master主观下线。默认为30s

客观下线(ODOWN, Objectively down)
客观下线需要多个哨兵(quorum个)达成意见一致才能认为master客观上已经宕机

  • sentinel monitor <master-name> <ip> <redis-port> <quorum> quorum是判断ODOWN的一个阈值,超过该数量的哨兵认为master已经宕机,才会开始重新选举master,进行故障转移。这是因为有时候sentinel因为自身的网络问题,无法连接到master,并不是master的问题,所以需要多个sentinel都认为master宕机,才可以进行下一步操作。这保证了公平性和高可用。

哨兵中的Leader
当多数哨兵都认为master宕机后,需要进行master选举。谁来主导这个过程呢?不可能所有的哨兵都参与,那会造成混乱,此时就需要在哨兵中选举出一个Leader,主导整个故障转移(failover)过程。

当主节点被判断客观下线后,各个哨兵会进行协商,先选举一个Leader,并由该Leader节点进行故障转移(failover)。这个过程在sentinel的日志文件中有体现。

Leader节点的选举算法为:Raft算法(优化版的Paxos算法)

哨兵Leader推动Failover

  • 选新Master:选举范围是所有健康的slave。比较次序:replica-priority配置项(越小优先级越高) > replication offset(大者胜出) > run id(小者胜出,字典序,该值在redis启动时随机生成)
  • slave换主:Sentinel Leader向新master发送slaveof no one命令,让该节点变为master节点,Sentinel Leader向其他slave节点发送slaveof 新masterip 新masterport让slave换主
  • 旧master降级:当旧master重启后,Sentinel Leader会让它降级为slave并恢复正常工作

注意事项

  • 哨兵节点的数量应为多个,哨兵本身应该为集群,保证高可用
  • 哨兵节点的数量应该是奇数
  • 各个哨兵节点的配置应一致
  • 如果哨兵节点部署在Docker等容器里面,尤其要注意端口的正确映射
  • 哨兵集群+主从复制,并不能保证数据零丢失,因为master宕机后,选举新的master需要一定的时间,在这期间redis处于不可写的状态