Redis 哨兵(Sentinel)

在生产过程中,我们会遇到主master从slave切换,当主(master)服务器出现redis服务器异常,主机断电,磁盘损坏,等问题时候后,而redis主从复制无法实现自动的故障转移(将slave 自动提升为新
master),需要手动把一台从服务器切换为主服务器,这个步骤需要人工切换,费时费力,还有可能造成"事故",另外也无法横向扩展Redis服务的并行写入性能,当单台Redis服务器性能无法满足业务写入需求的时候,也需要解决以上的两个核心问题所以这个时候我们会哨兵模式帮我们解决,从而帮助我们实现多台服务器并行写入已实现更高的并发问题的目的.

下面我们我们介绍下

详解,Redis 哨兵(Sentinel)工作原理,实现及哨兵运维

哨兵(Sentinel)工作原理概述

sentinel 架构和故障转移
详解,Redis 哨兵(Sentinel)工作原理,实现及哨兵运维

详解,Redis 哨兵(Sentinel)工作原理,实现及哨兵运维
详解,Redis 哨兵(Sentinel)工作原理,实现及哨兵运维

Sentinel 进程是用于监控redis集群中Master主服务器工作的状态,在Master主服务器发生故障的时候,可以实现Master和Slave服务器的切换,保证系统的高可用,此功能在redis2.6+的版本已引用,Redis的哨兵模式到了2.8版本之后就稳定了下来。一般在生产环境也建议使用Redis的2.8版本的以后版本

哨兵(Sentinel) 是一个分布式系统,可以在一个架构中运行多个哨兵(sentinel) 进程,这些进程使用流言协议(gossip protocols)来接收关于Master主服务器是否下线的信息,并使用投票协议(Agreement Protocols)来决定是否执行自动故障迁移,以及选择哪个Slave作为新的Master

每个哨兵(Sentinel)进程会向其它哨兵(Sentinel)、Master、Slave定时发送消息,以确认对方是否”活”着,如果发现对方在指定配置时间(此项可配置)内未得到回应,则暂时认为对方已离线,也就是所谓的”主观认为宕机” (主观:是每个成员都具有的独自的而且可能相同也可能不同的意识),英文名称:Subjective Down,简称SDOWN

主观下线和客观下线

有主观宕机,对应的有客观宕机。当“哨兵群”中的多数Sentinel进程在对Master主服务器做出SDOWN的判断,并且通过 SENTINEL is-master-down-by-addr 命令互相交流之后,得出的Master Server下线判断,这种方式就是“客观宕机”(客观:是不依赖于某种意识而已经实际存在的一切事物),英文名称是:Objectively Down, 简称 ODOWN

  • 当一个主服务器被判定为客观下线以后,监视这个服务器的各个Sentinel会进行协商,选举出一个领头的Sentinel,并由领头Sentinel对下线主服务器进行故障转移。
  • 每经过一次选举,无论选举成功还是失败,每隔sentinel实例的配置纪元都会自增1,每个新的纪元中,任何一个sentinel都有可能成为领头Sentinel。

通过一定的vote算法,从剩下的slave从服务器节点中,选一台提升为Master服务器节点,然后自动修改相关配置,并开启故障转移(failover)

Sentinel 机制可以解决master和slave角色的自动切换问题,但单个 Master 的性能瓶颈问题无法解决,类似于MySQL中的MHA功能

注意事项:

  • Redis Sentinel中的Sentinel节点个数应该为大于等于3且最好为奇数
  • 客户端初始化时连接的是Sentinel节点集合,不再是具体的Redis节点,但Sentinel只是配置中心不是代理
  • Redis Sentinel 节点与普通redis 没有区别,要实现读写分离依赖于客户端程序
  • redis 3.0 之前版本中,生产环境一般使用哨兵模式,但3.0后推出redis cluster功能后,可以支持更大规模的生产环境

sentinel中的三个定时任务

  • 第一个定时

  • 每10秒每个sentinel对master和slave执行info

    • 发现slave节点
    • 确认主从关系

详解,Redis 哨兵(Sentinel)工作原理,实现及哨兵运维

  • 第二个定时

  • 每2秒每个sentinel通过master节点的channel交换信息(pub/sub)

    • 通过sentinel__:hello频道交互
    • 交互对节点的“看法”和自身信息
      详解,Redis 哨兵(Sentinel)工作原理,实现及哨兵运维
  • 第三个定时

  • 每1秒每个sentinel对其他sentinel和redis执行ping

    心跳检测,失败判定的依据

详解,Redis 哨兵(Sentinel)工作原理,实现及哨兵运维

如何实现哨兵

详解,Redis 哨兵(Sentinel)工作原理,实现及哨兵运维
注意哨兵的准备实现主从复制架构

哨兵的前提是已经实现了一个redis的主从复制的运行环境,从而实现一个一主两从基于哨兵的高可用redis架构
注意: master 的配置文件中masterauth 和slave 都必须相同
master和slave同步过程
1、从节点主动向主节点发送同步请求

2、主节点接收到从的消息后发送自己的runid和offset发送给从节点

3、从节点保存主节点发送过来的runid和offset

4、主节点后台执行RDB持久化,并将新写入的数据写入到缓冲区中

5、主节点将RDB文件发送到从节点

6、主节点在把RDB文件发送到从节点后,把buffer中的数据以redis协议格式发送到从节点

7、从节点清空自己旧的数据

8、从节点把主节点推送过来的RDB文件中的数据载入内存,再加载所有缓冲区中的内容完成全量同步

9、全量同步完成后,如从节点需要继续同步增量数据的话,会先将自己的offset位置发送给主节点,主节点在收到后会根据从节点的offset,将从节点offset位置之后的数据发送回从节点,同时也将在缓冲区的数据也发送给从节点

所有主从节点的redis.conf中关健配置

实践范例:

#在所有主从节点执行
[root@centos8 ~]#dnf -y install redis
[root@centos8 ~]#vim /etc/redis.conf
bind 0.0.0.0
masterauth "123456"
requirepass "123456"
#或者非交互执行

[root@centos8 ~]#sed -i -e 's/bind 127.0.0.1/bind 0.0.0.0/' -e 's/^# masterauth
.*/masterauth 123456/' -e 's/^# requirepass .*/requirepass 123456/'
/etc/redis.conf
#在所有从节点执行

[root@centos8 ~]#echo "replicaof 10.0.0.8 6379" >> /etc/redis.conf
#在所有主从节点执行

[root@centos8 ~]#systemctl enable --now redis

master服务器状态

[root@redis-master ~]#redis-cli -a 123456
Warning: Using a password with '-a' or '-u' option on the command line interface
may not
127.0.0.1:6379> INFO replication
# Replication
role:master
connected_slaves:2
slave0:ip=10.0.0.28,port=6379,state=online,offset=112,lag=1
slave1:ip=10.0.0.18,port=6379,state=online,offset=112,lag=0
master_replid:8fdca730a2ae48fb9c8b7e739dcd2efcc76794f3
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:112
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:112
127.0.0.1:6379>

配置slave1

[root@redis-slave1 ~]#redis-cli -a 123456
Warning: Using a password with '-a' or '-u' option on the command line interface
may not be safe.
127.0.0.1:6379> REPLICAOF 10.0.0.8 6379
OK
127.0.0.1:6379> CONFIG SET masterauth "123456"
OK
127.0.0.1:6379> INFO replication
# Replication
role:slave
master_host:10.0.0.8
master_port:6379
master_link_status:up
master_last_io_seconds_ago:4
master_sync_in_progress:0
slave_repl_offset:140
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:8fdca730a2ae48fb9c8b7e739dcd2efcc76794f3
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:140
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_

配置slave2

[root@redis-slave2 ~]#redis-cli -a 123456
Warning: Using a password with '-a' or '-u' option on the command line interface
may not be safe.
127.0.0.1:6379> REPLICAOF 10.0.0.8 6379
OK
127.0.0.1:6379> CONFIG SET masterauth "123456"
OK
127.0.0.1:6379> INFO replication
# Replication
role:slave
master_host:10.0.0.8
master_port:6379
master_link_status:up
master_last_io_seconds_ago:3
master_sync_in_progress:0
slave_repl_offset:182
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:8fdca730a2ae48fb9c8b7e739dcd2efcc76794f3
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:182
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:15
repl_backlog_histlen:168
127.0.0.1:6379>

编辑哨兵的配置文件

sentinel配置

  • Sentinel实际上是一个特殊的redis服务器,有些redis指令支持,但很多指令并不支持.默认监听在26379/tcp端口.
  • 哨兵可以不和Redis服务器部署在一起,但一般部署在一起,所有redis节点使用相同的以下示例的配置文件
#如果是编译安装,在源码目录有sentinel.conf,复制到安装目录即可,
如:/apps/redis/etc/sentinel.conf

[root@centos8 ~]#vim /etc/redis-sentinel.conf
bind 0.0.0.0
port 26379
daemonize yes
pidfile "redis-sentinel.pid"
logfile "sentinel_26379.log"
dir "/tmp"  #工作目录

sentinel monitor mymaster 10.0.0.8 6379 2 #指定当前mymaster集群中master服务器的地址和端口
#2为法定人数限制(quorum),即有几个sentinel认为master down了就进行故障转移,一般此值是所有sentinel节点(一般总数是>=3的 奇数,如:3,5,7等)的一半以上的整数值,比如,总数是3,即3/2=1.5,取整为2,是master的ODOWN客观下线的依据

sentinel auth-pass mymaster 123456 #mymaster集群中master的密码,注意此行要在上面行的下面

sentinel down-after-milliseconds mymaster 30000 #(SDOWN)判断mymaster集群中所有节点的主观下线的时间,单位:毫秒,建议3000

sentinel parallel-syncs mymaster 1 #发生故障转移后,同时向新master同步数据的slave数量,数字越小总同步时间越长,但可以减轻新master的负载压力

sentinel failover-timeout mymaster 180000 #所有slaves指向新的master所需的超时时间,单位:毫秒

sentinel deny-scripts-reconfig yes #禁止修改脚本

logfile /var/log/redis/sentinel.log

三个哨兵服务器的配置都如下

[root@redis-master ~]#grep -vE "^#|^$" /etc/redis-sentinel.conf
port 26379
daemonize no
pidfile "/var/run/redis-sentinel.pid"
logfile "/var/log/redis/sentinel.log"
dir "/tmp"
sentinel monitor mymaster 10.0.0.8 6379 2  #修改此行
sentinel auth-pass mymaster 123456 #增加此行
sentinel down-after-milliseconds mymaster 3000  #修改此行
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000
sentinel deny-scripts-reconfig yes
#以下内容自动生成,不需要修改
sentinel myid 50547f34ed71fd48c197924969937e738a39975b  #此行自动生成必须唯一,修改此
值需重启redis和sentinel服务
.....
# Generated by CONFIG REWRITE
protected-mode no
supervised systemd
sentinel leader-epoch mymaster 0
sentinel known-replica mymaster 10.0.0.28 6379
sentinel known-replica mymaster 10.0.0.18 6379
sentinel current-epoch 0

[root@redis-master ~]#scp /etc/redis-sentinel.conf redis-slave1:/etc/

[root@redis-master ~]#scp /etc/redis-sentinel.conf redis-slave2:/etc/

启动哨兵

三台哨兵服务器都要启动

#确保每个哨兵主机myid不同
[root@redis-slave1 ~]#vim /etc/redis-sentinel.conf
sentinel myid 50547f34ed71fd48c197924969937e738a39975c
[root@redis-slave2 ~]#vim /etc/redis-sentinel.conf
sentinel myid 50547f34ed71fd48c197924969937e738a39975d
[root@redis-master ~]#systemctl enable --now redis-sentinel.service
[root@redis-slave1 ~]#systemctl enable --now redis-sentinel.service
[root@redis-slave2 ~]#systemctl enable --now redis-sentinel.service

如果是编译安装,在所有哨兵服务器执行下面操作启动哨兵

#vim /apps/redis/etc/sentinel.conf
bind 0.0.0.0
port 26379
daemonize yes
pidfile "redis-sentinel.pid"
Logfile "sentinel_26379.log"
dir "/apps/redis/data"
sentinel monitor mymaster 10.0.0.8 6379 2
sentinel auth-pass mymaster 123456
sentinel down-after-milliseconds mymaster 15000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000
sentinel deny-scripts-reconfig yes

#/apps/redis/bin/redis-sentinel /apps/redis/etc/sentinel.conf

验证哨兵端口

[root@redis-master ~]#ss -ntl
State    Recv-Q    Send-Q   Local Address:Port   Peer Address:Port
   
LISTEN    0       128        0.0.0.0:22       0.0.0.0:*  
  
LISTEN    0       128        0.0.0.0:26379     0.0.0.0:*  
  
LISTEN    0       128        0.0.0.0:6379      0.0.0.0:*  
  
LISTEN    0       128         [::]:22        [::]:*  
  
LISTEN    0       128         [::]:26379      [::]:*  
  
LISTEN    0       128         [::]:6379       [::]:*

查看哨兵日志

master的哨兵日志

[root@redis-master ~]#tail -f /var/log/redis/sentinel.log
38028:X 20 Feb 2020 17:13:08.702 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
38028:X 20 Feb 2020 17:13:08.702 # Redis version=5.0.3, bits=64,
commit=00000000, modified=0, pid=38028, just started
38028:X 20 Feb 2020 17:13:08.702 # Configuration loaded
38028:X 20 Feb 2020 17:13:08.702 * supervised by systemd, will signal readiness
38028:X 20 Feb 2020 17:13:08.703 * Running mode=sentinel, port=26379.
38028:X 20 Feb 2020 17:13:08.703 # WARNING: The TCP backlog setting of 511
cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower
value of 128.
38028:X 20 Feb 2020 17:13:08.704 # Sentinel ID is
50547f34ed71fd48c197924969937e738a39975b
38028:X 20 Feb 2020 17:13:08.704 # +monitor master mymaster 10.0.0.8 6379 quorum
2
38028:X 20 Feb 2020 17:13:08.709 * +slave slave 10.0.0.28:6379 10.0.0.28 6379 @
mymaster 10.0.0.8 6379
38028:X 20 Feb 2020 17:13:08.709 * +slave slave 10.0.0.18:6379 10.0.0.18 6379 @
mymaster 10.0.0.8 6379

slave的哨兵日志

root@redis-slave1 ~]#tail -f /var/log/redis/sentinel.log
25509:X 20 Feb 2020 17:13:27.435 * Removing the pid file.
25509:X 20 Feb 2020 17:13:27.435 # Sentinel is now ready to exit, bye bye...
25572:X 20 Feb 2020 17:13:27.448 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
25572:X 20 Feb 2020 17:13:27.448 # Redis version=5.0.3, bits=64,
commit=00000000, modified=0, pid=25572, just started
25572:X 20 Feb 2020 17:13:27.448 # Configuration loaded
25572:X 20 Feb 2020 17:13:27.448 * supervised by systemd, will signal readiness
25572:X 20 Feb 2020 17:13:27.449 * Running mode=sentinel, port=26379.
25572:X 20 Feb 2020 17:13:27.449 # WARNING: The TCP backlog setting of 511
cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower
value of 128.
25572:X 20 Feb 2020 17:13:27.449 # Sentinel ID is
50547f34ed71fd48c197924969937e738a39975b
25572:X 20 Feb 2020 17:13:27.449 # +monitor master mymaster 10.0.0.8 6379 quorum2

当前sentinel状态

在sentinel状态中尤其是最后一行,涉及到masterIP是多少,有几个slave,有几个sentinels,必须是符合全部服务器数量

[root@redis-master ~]#redis-cli -p 26379
127.0.0.1:26379> INFO sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=10.0.0.8:6379,slaves=2,sentinels=3 #两个
slave,三个sentinel服务器,如果sentinels值不符合,检查myid可能冲突

停止Redis Master测试故障转移

[root@redis-master ~]#killall redis-server

查看各节点上哨兵信息:

[root@redis-master ~]#redis-cli -a 123456 -p 26379
Warning: Using a password with '-a' or '-u' option on the command line interface
may not be safe.
127.0.0.1:26379> INFO sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=10.0.0.18:6379,slaves=2,sentinels=2