it领域往往都是面试造火箭,实际工作拧螺丝。为了更好的应对面试,让大家能拿到更高的offer✉,我们接下来就讲讲“造火箭”的事情🧑🚀。
1.redis哨兵
主从结构中master节点的作用非常重要,一旦故障就会导致集群不可用。那么有什么办法能保证主从集群的高可用性呢?
1.1.哨兵工作原理
redis提供了哨兵
(sentinel
)💂 机制来监控主从集群监控状态,确保集群的高可用性。
1.1.1.哨兵作用
哨兵集群作用原理图:
哨兵的作用如下:
-
💠状态监控 📹:
sentinel
会不断检查您的master
和slave
是否按预期工作。 -
💠故障恢复(failover)🔁:如果
master
故障,sentinel
会将一个slave
提升为master
。当故障实例恢复后会成为slave。
-
💠状态通知⁉️:
sentinel
充当redis
客户端的服务发现来源,当集群发生failover
时,会将最新集群信息推送给redis
的客户端。
那么问题来了,sentinel
怎么知道一个redis节点是否宕机呢?
1.1.2.状态监控
sentinel
基于心跳机制监测服务状态,每隔1秒向集群的每个节点发送ping命令,并通过实例的响应结果来做出判断:
-
🔹主观下线(sdown):如果某sentinel节点发现某redis节点未在规定时间响应,则认为该节点主观下线。
-
🔹 客观下线(odown):若超过指定数量(通过
quorum
设置)的sentinel都认为该节点主观下线,则该节点客观下线。quorum值最好超过sentinel节点数量的一半,sentinel节点数量至少3台。
如图:
一旦发现master故障,sentinel需要在salve中选择一个作为新的master,选择依据是这样的:
对应的官方文档如下:
https://redis.io/docs/management/sentinel/#replica-selection-and-priority
💡 问题来了,当选出一个新的master后,该如何实现身份切换呢?
1.1.3.选举leader
首先,sentinel集群要选出一个执行failover
的sentinel节点,可以成为leader
。要成为leader
要满足两个条件:
不难看出,谁先投票,谁就会称为leader,那什么时候会触发投票呢?
答案是第一个确认master客观下线的人会立刻发起投票,一定会成为leader。
ok,sentinel
找到leader
以后,该如何完成failover
呢?
1.1.4.failover
我们举个例子,有一个集群,初始状态下7001为master
,7002和7003为slave
:
假如master发生故障,slave1当选。则故障转移的流程如下:
1)sentinel
给备选的slave1
节点发送slaveof no one
命令,让该节点成为master
2)sentinel
给所有其它slave
发送slaveof 192.168.150.101 7002
🖥命令,让这些节点成为新master
,也就是7002
的slave
节点,开始从新的master
上同步数据。
3)最后,当故障节点恢复后会接收到哨兵信号,执行slaveof 🖥192.168.150.101 7002
命令,成为slave
:
1.2.搭建哨兵集群
首先,我们停掉之前的redis集群:
# 老版本dockercompose
docker-compose down
# 新版本docker
docker compose down
资料提供的sentinel.conf 📄文件:
其内容如下:
sentinel announce-ip "192.168.150.101"
sentinel monitor hmaster 192.168.150.101 7001 2
sentinel down-after-milliseconds hmaster 5000
sentinel failover-timeout hmaster 60000
说明:
-
🏳️🌈 sentinel announce-ip "192.168.150.101"
:声明当前sentinel的ip -
🏳️🌈 sentinel monitor hmaster 192.168.150.101 7001 2
:指定集群的主节点信息-
🚩 hmaster
:主节点名称,自定义,任意写 -
🚩 192.168.150.101 7001
:主节点的ip和端口 -
🚩2
:认定master
下线时的quorum
值
-
🏳️🌈 sentinel down-after-milliseconds hmaster 5000
:声明master节点超时多久后被标记下线🏳️🌈 sentinel failover-timeout hmaster 60000
:在第一次故障转移失败后多久再次重试
我们在虚拟机的/root/redis
目录下新建3个文件夹:s1
、s2
、s3
:
将课前资料提供的sentinel.conf
文件分别拷贝一份到3个文件夹中。
接着修改docker-compose.yaml
文件,内容如下:
version: "3.2"
services:
r1:
image: redis
container_name: r1
network_mode: "host"
entrypoint: ["redis-server", "--port", "7001"]
r2:
image: redis
container_name: r2
network_mode: "host"
entrypoint: ["redis-server", "--port", "7002", "--slaveof", "192.168.150.101", "7001"]
r3:
image: redis
container_name: r3
network_mode: "host"
entrypoint: ["redis-server", "--port", "7003", "--slaveof", "192.168.150.101", "7001"]
s1:
image: redis
container_name: s1
volumes:
- /root/redis/s1:/etc/redis
network_mode: "host"
entrypoint: ["redis-sentinel", "/etc/redis/sentinel.conf", "--port", "27001"]
s2:
image: redis
container_name: s2
volumes:
- /root/redis/s2:/etc/redis
network_mode: "host"
entrypoint: ["redis-sentinel", "/etc/redis/sentinel.conf", "--port", "27002"]
s3:
image: redis
container_name: s3
volumes:
- /root/redis/s3:/etc/redis
network_mode: "host"
entrypoint: ["redis-sentinel", "/etc/redis/sentinel.conf", "--port", "27003"]
直接运行命令,启动集群:
docker-compose up -d
运行结果:
我们以s1节点为例,查看其运行日志:
# sentinel id is 8e91bd24ea8e5eb2aee38f1cf796dcb26bb88acf
# +monitor master hmaster 192.168.150.101 7001 quorum 2
* +slave slave 192.168.150.101:7003 192.168.150.101 7003 @ hmaster 192.168.150.101 7001
* +sentinel sentinel 5bafeb97fc16a82b431c339f67b015a51dad5e4f 192.168.150.101 27002 @ hmaster 192.168.150.101 7001
* +sentinel sentinel 56546568a2f7977da36abd3d2d7324c6c3f06b8d 192.168.150.101 27003 @ hmaster 192.168.150.101 7001
* +slave slave 192.168.150.101:7002 192.168.150.101 7002 @ hmaster 192.168.150.101 7001
可以看到sentinel
已经联系到了7001
这个节点,并且与其它几个哨兵也建立了链接。哨兵信息如下:
-
☑️
27001
:sentinel id
是8e91bd24ea8e5eb2aee38f1cf796dcb26bb88acf
-
☑️27002
:sentinel id
是5bafeb97fc16a82b431c339f67b015a51dad5e4f
-
☑️27003
:sentinel id
是56546568a2f7977da36abd3d2d7324c6c3f06b8d
1.3.演示failover
接下来,我们演示一下当主节点故障时,哨兵是如何完成集群故障恢复(failover)的。
我们连接7001
这个master
节点,然后通过命令让其休眠60秒,模拟宕机:
# 连接7001这个master节点,通过sleep模拟服务宕机,60秒后自动恢复
docker exec -it r1 redis-cli -p 7001 debug sleep 60
稍微等待一段时间后,会发现sentinel节点触发了failover
:
1.4.总结
sentinel的三个作用是什么?
-
📛集群监控
-
📛故障恢复
-
📛状态通知
sentinel如何判断一个redis实例是否健康?
-
✅每隔1秒发送一次ping命令,如果超过一定时间没有相向则认为是主观下线(
sdown
) -
✅如果大多数sentinel都认为实例主观下线,则判定服务客观下线(
odown
)
故障转移步骤有哪些?
-
✅首先要在
sentinel
中选出一个leader
,由leader执行failover
-
✅选定一个
slave
作为新的master
,执行slaveof noone
,切换到master模式 -
✅然后让所有节点都执行
slaveof
新master -
✅ 修改故障节点配置,添加
slaveof
新master
sentinel选举leader的依据是什么?
-
☑️票数超过sentinel节点数量1半
-
☑️票数超过quorum数量
-
☑️一般情况下最先发起failover的节点会当选
sentinel从slave中选取master的依据是什么?
-
⭕首先会判断slave节点与master节点断开时间长短,如果超过
down-after-milliseconds
* 10
则会排除该slave节点 -
⭕然后判断slave节点的
slave-priority
值,越小优先级越高,如果是0则永不参与选举(默认都是1)。 -
⭕如果
slave-prority
一样,则判断slave节点的offset
值,越大说明数据越新,优先级越高 -
⭕最后是判断slave节点的
run_id
大小,越小优先级越高(通过info server可以查看run_id
)。
1.5.redistemplate连接哨兵集群(自学)
分为三步:
-
1)引入依赖
-
2)配置哨兵地址
-
3)配置读写分离
1.5.1.引入依赖
就是springdataredis的依赖:
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-data-redis</artifactid>
</dependency>
1.5.2.配置哨兵地址
连接哨兵集群与传统单点模式不同,不再需要设置每一个redis的地址,而是直接指定哨兵地址:
spring:
redis:
sentinel:
master: hmaster # 集群名
nodes: # 哨兵地址列表
- 192.168.150.101:27001
- 192.168.150.101:27002
- 192.168.150.101:27003
1.5.3.配置读写分离
最后,还要配置读写分离,让java客户端将写请求发送到master节点,读请求发送到slave节点。定义一个bean即可:
@bean
public lettuceclientconfigurationbuildercustomizer clientconfigurationbuildercustomizer(){
return clientconfigurationbuilder -> clientconfigurationbuilder.readfrom(readfrom.replica_preferred);
}
这个bean中配置的就是读写策略,包括四种:
-
master
:从主节点读取 -
master_preferred
:优先从master
节点读取,master
不可用才读取slave
-
replica
:从slave
节点读取 -
replica_preferred
:优先从slave
节点读取,所有的slave
都不可用才读取master
发表评论