【Redis】Redis高级:哨兵

Redis高级:哨兵

Redis主从集群中的从节点宕机后,可以通过主节点来做数据的同步,但是如果宕机的是主节点,那该怎么处理呢?

如果主节点在宕机之前刚好做了数据的持久化,那自然是不用担心数据安全问题的,但是主节点是负责写操作的,而从节点是只读的,如果主节点一直宕机,那么Redis就无法处理来自用户的写操作命令,这显然是不行的

Redis提供了哨兵(Sentinel)机制来实现主从集群的自动故障恢复。

1 哨兵原理

1.1 集群结构和作用

哨兵并不是Redis集群的一部分,而是独立于Redis集群的另外一个集群。整体结构如图:

【Redis】Redis高级:哨兵_第1张图片

哨兵的作用如下:

  • 监控:Sentinel会不断检查master和slave是否按预期工作
  • 自动故障恢复:如果master故障,Sentinel会将一个slave提升为master。当故障的master恢复之后也以新的master为主
  • 通知:Sentinel可以充当Redis客户端的服务发现来源,Redis客户端无需再直接连接Redis节点,而是连接Sentinel,由Sentinel提供主从节点的地址信息,当集群发生故障转移,即有slave被提升为master后,Sentinel 会将服务状态的变更通知 Redis 客户端,这样 Redis 客户端就可以知道新的主从节点了,从而改变节点的访问地址。

1.2 集群监控原理

Sentinel基于心跳机制来监测服务状态是否正常,Sentinel每隔1秒会向集群的每个实例发送一次ping命令

  • 主观下线:如果某Sentinel节点发现某实例未在规定时间响应,则认为该实例主观下线。
  • 客观下线:若超过指定数量(quorum)的Sentinel都认为该实例主观下线,则该实例客观下线。quorum值是我们自己设定的,最好超过Sentinel实例数量的一半。

【Redis】Redis高级:哨兵_第2张图片

一旦Sentinel集群认定了master客观下线后,会从现有的slave中选择一个作为新的master

1.3 集群故障恢复原理

一旦发现master故障,sentinel会从现有的salve中选择一个作为新的master,具体选择哪个slave,需要经过以下判断:

  • 首先会判断slave节点与master节点距离上一次同步的时间长短,如果超过指定值(down-after-milliseconds * 10,由我们自己设定)则说明该节点的数据较旧,会首先排除该slave节点
  • 然后判断slave节点的slave-priority值,越小优先级越高,为0则永不参与选举,一般来说,如果我们不主动设置slave-priority,则所有节点的slave-priority都是一样的
  • 如果slave-prority一样,则判断slave节点的offset值,越大说明数据越新,优先级越高
  • 如果通过offset值仍然不能判断出优先级,那就说明选哪个slave成为新的master已经没有什么区别了,这时就会根据slave节点的运行id大小来判断,id越小优先级越高。

当选出一个新的master后,Sentinel又是如何实现主从切换的呢?整理流程如下:

  • Sentinel给备选的slave1节点发送slaveof no one命令,让该节点成为master
  • Sentinel给所有其它slave发送slaveof 192.168.150.101 7002 命令,让这些slave成为新master的从节点,开始从新的master上同步数据。
  • 最后,sentinel将故障节点标记为slave,当故障节点恢复后会自动成为新的master的slave节点

【Redis】Redis高级:哨兵_第3张图片


2 搭建哨兵集群

2.1 集群结构

这里我们搭建一个三节点形成的Sentinel集群,来监管Redis主从集群。如图:

【Redis】Redis高级:哨兵_第4张图片

三个sentinel实例信息如下:

节点 IP PORT
s1 192.168.211.100 27001
s2 192.168.211.100 27002
s3 192.168.211.100 27003

搭建主从集群可以参考我的上一篇文章:【Redis】Redis高级:主从

2.2 准备实例和配置

要在同一台虚拟机开启3个实例,必须准备三份不同的配置文件和目录,配置文件所在目录也就是工作目录。我这里Redis的安装目录在/usr/local/redis-6.2.6,以下操作将以这个目录为参考。

另外需要注意,以下所有操作都是在redis没有设置密码的情况下,如果你的redis设置了密码,则操作会更复杂一些。

首先创建三个文件夹,名字分别叫s1、s2、s3:

# 进入/local目录
cd /usr/local
# 创建目录
mkdir s1 s2 s3

然后我们在s1目录创建一个sentinel.conf文件,添加下面的内容:

# 当前sentinel实例的端口
port 27001
# 指定sentinel的ip地址为当前虚拟机的ip地址
sentinel announce-ip 192.168.211.100
# 指定主节点信息
# mymaster 为主节点名称,为自定义
# 192.168.150.101 7001 为主节点的ip与端口
# 2 为quorum值,即当超过2个sentinel认为某节点主观下线时,该节点客观下线
sentinel monitor mymaster 192.168.211.100 7001 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000
# 配置文件所在目录
dir "/usr/local/s1"

然后将s1/sentinel.conf文件拷贝到s2、s3两个目录中(在/local目录执行下列命令):

# 方式一:逐个拷贝
cp s1/sentinel.conf s2
cp s1/sentinel.conf s3
# 方式二:管道组合命令,一键拷贝
echo s2 s3 | xargs -t -n 1 cp s1/sentinel.conf

修改s2、s3两个文件夹内的配置文件,将端口分别修改为27002、27003(在/local目录下执行命令):

sed -i -e 's/27001/27002/g' -e 's/s1/s2/g' s2/sentinel.conf
sed -i -e 's/27001/27003/g' -e 's/s1/s3/g' s3/sentinel.conf

2.3 启动与测试

注意:进行sentinel的测试之前需要先将Redis主从环境搭建并运行

为了方便查看日志,我们另外打开3个ssh窗口,分别执行以下命令:

# 第1个
redis-sentinel /usr/local/s1/sentinel.conf
# 第2个
redis-sentinel /usr/local/s2/sentinel.conf
# 第3个
redis-sentinel /usr/local/s3/sentinel.conf

出现了如下界面,就说明成功了

这时我们就可以尝试让主节点宕机,同时观察redis-sentinel运行的ssh窗口的变化,笔者经过测试是没问题的,7001宕机之后,7003当选成为了新的master,大家也可以自行尝试一下

【Redis】Redis高级:哨兵_第5张图片


3 RedisTemplate连接哨兵

在Sentinel集群监管下的Redis主从集群,其主从节点的身份会因为自动故障转移而发生变化,Redis的客户端必须感知这种变化,及时更新连接信息。Spring的RedisTemplate底层利用lettuce实现了节点的感知和自动切换,这一过程是全自动的,我们只需要经过简单的配置就可以实现。

具体配置如下:

1)在boot项目的pom文件中导入依赖

 <dependency>
 	<groupId>org.springframework.bootgroupId>
	<artifactId>spring-boot-starter-data-redisartifactId>
 dependency>

2)在application.yml中指定sentinel相关信息:

spring:
  redis:
    sentinel:
      master: mymaster # master名称,需要与sentnel配置信息中的master名称一致
      nodes:
        - 192.168.150.101:27001 # sentinel节点1
        - 192.168.150.101:27002 # sentinel节点2
        - 192.168.150.101:27003 # sentinel节点3

3)在项目的启动类中,添加一个新的bean,这个bean是用来做Redis集群的读写分离的

@Bean
public LettuceClientConfigurationBuilderCustomizer clientConfigurationBuilderCustomizer(){
    return clientConfigurationBuilder -> clientConfigurationBuilder.readFrom(ReadFrom.REPLICA_PREFERRED);
}

bean中配置的信息是读写策略,包括四种可选项:

  • MASTER:从master读取
  • MASTER_PREFERRED:优先从master节点读取,master不可用才读取slave
  • REPLICA:从slave节点读取
  • REPLICA _PREFERRED:优先从slave节点读取,所有的slave都不可用才读取master

上述配置完毕之后,我们就可以正常使用RedisTemplate来对redis集群进行操作,如果集群中的master宕机了,sentinel就会自动选举新的master,并将新master的信息发送给该Java程序,这样Java程序就可以对新master进行写操作而对其他节点进行读操作了。而这一过程都是自动完成的,无需我们过多关注

你可能感兴趣的:(#,Redis,redis,数据库,java)