Redis主从集群中的从节点宕机后,可以通过主节点来做数据的同步,但是如果宕机的是主节点,那该怎么处理呢?
如果主节点在宕机之前刚好做了数据的持久化,那自然是不用担心数据安全问题的,但是主节点是负责写操作的,而从节点是只读的,如果主节点一直宕机,那么Redis就无法处理来自用户的写操作命令,这显然是不行的
Redis提供了哨兵(Sentinel)机制来实现主从集群的自动故障恢复。
哨兵并不是Redis集群的一部分,而是独立于Redis集群的另外一个集群。整体结构如图:
哨兵的作用如下:
Sentinel基于心跳机制来监测服务状态是否正常,Sentinel每隔1秒会向集群的每个实例发送一次ping命令
一旦Sentinel集群认定了master客观下线后,会从现有的slave中选择一个作为新的master
一旦发现master故障,sentinel会从现有的salve中选择一个作为新的master,具体选择哪个slave,需要经过以下判断:
当选出一个新的master后,Sentinel又是如何实现主从切换的呢?整理流程如下:
这里我们搭建一个三节点形成的Sentinel集群,来监管Redis主从集群。如图:
三个sentinel实例信息如下:
节点 | IP | PORT |
---|---|---|
s1 | 192.168.211.100 | 27001 |
s2 | 192.168.211.100 | 27002 |
s3 | 192.168.211.100 | 27003 |
搭建主从集群可以参考我的上一篇文章:【Redis】Redis高级:主从
要在同一台虚拟机开启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
注意:进行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,大家也可以自行尝试一下
在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中配置的信息是读写策略,包括四种可选项:
上述配置完毕之后,我们就可以正常使用RedisTemplate来对redis集群进行操作,如果集群中的master宕机了,sentinel就会自动选举新的master,并将新master的信息发送给该Java程序,这样Java程序就可以对新master进行写操作而对其他节点进行读操作了。而这一过程都是自动完成的,无需我们过多关注