使用 Sentinel 实现 Redis 集群高可用部署

实战场景:公司的 redist 主从架构中,如果主服务器离线,那么所有写操作操作则无法执行。为了避免此情况发生,redis 引入了 sentinel(哨兵)机制,当 redis 主挂了,redis 从可以主动变成主。

1、Sentinel 概述和工作过程

1、Sentinel 作用:检测 Master 状态,如果 Master 异常,则会进行 Master-Slave 切换,将其中一个 Slave 作为 Master,将之前的 Master 作为 Slave 。
当 Master-Slave 切换后,master-redis.conf、slave-redis.conf 和 sentinel.conf 的内容都会发生改变,即 master-redis.conf 中会多一行 slaveof的配置,sentinel.conf 的监控目标会随之调换

2、Sentinel 工作方式

Sentinel 是 Redis 官方提供的一种高可用方案(除了 Sentinel,Redis Cluster 是另一种方案),它可以自动监控 Redis master/slave 的运行状态,如果发现 master 无法访问了,就会启动 failover 把其中一台可以访问的 slave 切换为 master。支持 Sentinel 的 Redis 客户端(例如 Java 的 Jedis)会在连接 Redis 服务器的时候向 Sentinel 询问 master 的 ip,并且会在收到 master 切换的 pub/sub 事件后自动重新连接到新的 master。对调用Redis 客户端的业务系统来说,这些都是完全透明的。 :::info 扩展:redis 主观下线和客观下线
主观下线:Subjectively Down,简称 SDOWN,指的是当前 Sentinel 实例对某个 redis 服务器做出的下线判断。 Subjectively [səəb’dʒʒektɪɪvlɪɪ] 主观地
客观下线:Objectively Down, 简称 ODOWN,指的是多个 Sentinel 实例在对 Master Server做出 SDOWN 判断,并且通过 SENTINEL is-master-down-by-addr 命令互相交流之后,得出的Master Server 下线判断,然后开启 failover。 Objectively [əəb’dʒʒektɪɪvlɪɪ] 客观地 :::

3、使用 Sentinel 实现 Redis 集群高可用部署

实验拓扑:
重新开启 3 台全新服务器,一定是全新的 3 台服务器,如果之前的实验环境上做,会出现配置混乱。
每台服务器上分别配置 redis 和 sentinel。其中 1 个 master 和 2 个 slave。如下图所示:
1、配置redis131 为 redis 主
[root@redis131 ~]# yum -y install epel-release
[root@redis131 ~]# yum -y install http://rpms.remirepo.net/enterprise/remi-release-7.rpm
[root@redis131 ~]# yum —enablerepo=remi install -y redis #安装 Redis。
2、在 redis132 主机上安装 Redis
[root@redis132 ~]# yum -y install epel-release
[root@redis132 ~]# yum -y install http://rpms.remirepo.net/enterprise/remi-release-7.rpm
[root@redis132 ~]# yum —enablerepo=remi install -y redis #安装 Redis。
3、在 redis133 主机上安装 Redis
[root@redis133 ~]# yum -y install epel-release
[root@redis133 ~]# yum -y install http://rpms.remirepo.net/enterprise/remi-release-7.rpm
[root@redis133 ~]# yum —enablerepo=remi install -y redis #安装 Redis。
4、修改redis131 主机上的 Redis 配置文件
[root@redis131 ~]# vim /etc/redis.conf

改:69 bind 127.0.0.1
为:69 bind 0.0.0.0 #redis 监听的地址,改为 0.0.0.0 表示在所有网卡接口上进行监听。
改:88 protected-mode yes
为:88 protected-mode no #关闭 protected-mode,允许外网访问redis 服务器。

[root@redis131 ~]# systemctl restart redis #重启服务。
[root@redis131 ~]# iptables -F
5、配置 redis132 主机为 redis 从服务器
[root@redis132 ~]# vim /etc/redis.conf #修改

改: bind 127.0.0.1
为: bind 0.0.0.0 #redis 监听的地址,改为 0.0.0.0 表示在所有网卡接口上进行监听。
改: protected-mode yes
为: protected-mode no
改: # replicaof <masterip> <masterport> 
为: replicaof 192.168.8.131 6379

[root@redis132 ~]# systemctl start redis #启动 redis。
[root@redis132 ~]# iptables -F
6、配置 redis133 主机为 redis 从服务器
[root@redis133 ~]# vim /etc/redis.conf #修改

改: bind 127.0.0.1
为: bind 0.0.0.0 #redis 监听的地址,改为 0.0.0.0 表示在所有网卡接口上进行监听。
改: protected-mode yes
为: protected-mode no
改: # replicaof <masterip> <masterport> 
为: replicaof 192.168.8.131 6379

[root@redis133 ~]# systemctl start redis #启动 redis。
[root@redis133 ~]# iptables -F
7、登录 redis133 主机上查看主从复制状态

[root@redis133 ~]# redis-cli #登录 redis。
127.0.0.1:6379> info replication
# Replication
role:slave #角色:slave。
master_host:192.168.8.131 #主服务器 IP。
master_port:6379 #主服务端口。
master_link_status:up #主服务器连接状态为 up,说明已经主从同步上了。

到此,1 主 2 从的 redis 主从复制架构已经搭建成功,下面开始配置 sentinel 架构构。
8、在redis131 上配置 sentinel1

[root@redis131 ~]# vim /etc/redis-sentinel.conf
改:17 # protected-mode no
为:17 protected-mode no
21 port 26379 #默认,保持不变
改:26 daemonize no
为:26 daemonize yes
改:84 sentinel monitor mymaster 127.0.0.1 6379 2
为:84 sentinel monitor mymaster 192.168.8.131 6379 2
注:# sentinel monitor <master-name> <ip> <redis-port> <quorum> 每项含意如下:
<master-name>为集群名称,可以自定义,如果同时监控有多组 redis 集群时,<master-name>不能一样。
<ip> 主节点的 IP 地址,<redis-port>主节点的端口号。
<quorum>主节点对应的quorum 法定数量,用于定义 Sentinel 的数量,是一个大于值尽量使用奇数,如果 Sentinel 有 3 个,则指定为 2 即可,如果有 4 个,不能够指定为 2,避免导致集群分裂。最后的数字 2 指定的值,表明如果有 2 个 sentinels 无法连接 master,才认为 master 挂了。
quorum [ˈˈkwɔɔ:rəəm] 法定人数
改:113 sentinel down-after-milliseconds mymaster 30000 #默认单位是毫秒,配成 10 秒
为:113 sentinel down-after-milliseconds mymaster 10000
121 sentinel parallel-syncs mymaster 1 #保存默认
parallel [ˈˈr pær əəlel] 平行
改:146 sentinel failover-timeout mymaster 180000
为:146 sentinel failover-timeout mymaster 60000

9、把 redis-sentinel.conf 发给 redis132 和 redis133
[root@redis131 ~]# scp /etc/redis-sentinel.conf 192.168.8.132:/etc/redis-sentinel.conf
[root@redis131 ~]# scp /etc/redis-sentinel.conf 192.168.8.133:/etc/redis-sentinel.conf
10、启动 Redis 和 sentinel 服务器
[root@redis131 ~]# systemctl start redis && systemctl start redis-sentinel
[root@redis132 ~]# systemctl start redis && systemctl start redis-sentinel
[root@redis133 ~]# systemctl start redis && systemctl start redis-sentinel
11、模拟故障
查看当前主从状态:
[root@redis131 ~]# redis-cli -h 192.168.8.132
192.168.1.64:6379> info replication
# Replication
role:slave
master_host:192.168.1.63
master_port:6379
[root@redis131 ~]# systemctl stop redis #在redis131 上关闭 master

[root@redis131 ~]# redis-cli -h 192.168.8.132
192.168.1.64:6379> info replication
# Replication
role:slave
master_host:192.168.1.62 #master 已经转移到 redis133 上了
master_port:6379

12、恢复redis131

[root@redis131 ~]# systemctl start redis
[root@redis131 ~]# redis-cli -h 192.168.1.63
192.168.1.63:6379> info replication
# Replication
role:slave
master_host:192.168.1.62 #主 redis 还是 redis133,并不会因为redis131 恢复成功后,就主动让出权限。 这样可以避免再次回切时,发生服务中断。
[root@redis133 ~]# redis-cli #登录主 redis 上查看从节点信息
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=192.168.1.64,port=6379,state=online,offset=988554,lag=0
slave1:ip=192.168.1.63,port=6379,state=online,offset=988554,lag=0 #

13、查看 Sentinel 信息

[root@redis131 ~]# redis-cli -h 192.168.1.63 -p 26379 #查看 Sentinel 信息。
[root@redis132 ~]# redis-cli -h 192.168.1.63 -p 26379
192.168.1.63: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=192.168.1.62:6379,slaves=2,sentinels=3
192.168.1.63:26379> exit

:::danger 注意:将来客户端应连接 Sentinel,向 Sentinel 发请求去寻址,并根据 Sentinel 的反馈,进行连接新的 Redis 主节点,这一点需要使用 Redis 专用客户端来实现。Redis 客户端会根据 Sentinel 返回的新节点 IP 进行连接。这一块是开发人员的事情了。如果 java 中的 JedisClient 就提供了使用 Sentinel的功能。 :::