Redis的高可用是通过哨兵Sentinel来保证的,如下:
思路是:通过运行监控服务器来保证服务的高可用。从Redis 2.8 版本开始,提供了一个稳定版本的Sentinel,用来解决高可用的问题。我们会启动奇数个Sentinel服务。Sentinel 本质只是一个运行在特殊模式下的Redis。Sentinel通过 info 命令得到被监听的 Redis 机器的 master slave 等信息。
为了保证监控服务器的可用性,我们会对Sentinel做集群的部署。Sentinel既监控所有的Redis服务,Sentinel之间也相互监控。另外,Sentinel本身没有主从之分,地位是平等的,只有Redis服务节点有主从之分。
各个 Sentinel 之间唯一的联系,就是他们监控相同的 master,那一个Sentinel节点怎么知道其他Sentinel节点的存在?答案是发布订阅(Pub/Sub)的功能。
Sentinel 是一个特殊状态的Redis节点,所有它也有发布订阅的功能。
哨兵上线时,给所有的Redis节点(包括master和node)的名字为 sentinel:hello 的 channel 发送消息。
每个哨兵都订阅了所有Redis节点名为 sentinel:hello 的channel,所有互相都能感知到对方的存在,而从进行监控。
Redis 主从结构,主节点宕机之后,对于所有的从节点,一共有四个因素影响选举结果,分别是断开连接时长、优先级排序、复制数量、进程Id。
1、如果与哨兵连接断开的比较久,超过某个阈值,就直接失去了选举权。
2、对于所有拥有选举权的从节点,看谁的优先级高,这个在配置文件中可以设置,默认优先级为100,数值越小优先级越高。
3、对于所有拥有选举权的从节点,如果有优先级相同,看哪个从节点从master中复制的数据最多(就是offset),选offset最大的那个。
4、对于所有拥有选举权的从节点,如果优先级和offset相同,选进程id最小的那个。
关于redis.conf中的 优先级,默认是 100
基本上redis.conf里面的属性,都可以在 redis-cli 可以查看,命令为
config get 属性名
“哨兵集群Sentinel”:哨兵是一个一个的,通过哨兵来完成四个功能:集群监控(master宕机了就要选主)、消息通知、故障转移、配置中心,囊括所有哨兵的集群就是Sentinel。
哨兵组件的四个功能:
1、集群监控:Snetinel 会不断检查主服务器和从服务器是否正常运行。
2、消息通知:如果某个被监控的实例出现了问题,Sentinel 可以通过 api 发出通知。
3、故障转移:如果主服务器发生故障,比如执行shutdown模拟宕机,Sentinel 可以启动故障转移功能,将某台从服务器升级为主服务器,自动选主,保证高可用。
4、配置中心:客户端redis-cli 连接到Sentinel,获取当前的Redis主服务器的地址。
最简单是Redis哨兵主从结构至少需要三个机器(通常哨兵/Redis节点都是奇数个)
为什么至少需要三个实例呢?我们先看看两个哨兵会咋样,如下图:
两个机器,每个机器上都是一个 redis节点6379端口 + 一个哨兵Sentinel 26379 端口,如下图:M1 表示 redis Master节点 6379端口,R1 表示 redis replication 节点 6379端口,S1 表示哨兵1(Master节点上),S2 表示哨兵2(Replication节点上/Slave节点上),如下图:
情况1:M1 6379端口宕机了,但是M1所在机器整个机器没有宕机
处理方式: s1和s2两个哨兵只要有一个(超过半数)认为你宕机了就切换了,并且会选举出一个哨兵去执行故障,但是这个时候也需要大多数哨兵都是运行的。M1宕机了,S1没挂那其实是OK的,
情况2:M1 所在机器整个机器都挂了,就是M1 和 S1都挂了
处理方式:哨兵就只剩下S2一个了,没有哨兵去允许故障转移了,虽然另外一个机器上还有R1,但是故障转移就是不执行。
经典的哨兵集群是这样的,三个机器,如下图:
情况:M1所在的机器挂了,M1 S1 都挂了
处理方式:哨兵还有两个,S2 和 S3,两个哨兵一看他不是挂了嘛,那我们就选举一个出来执行故障转移不就好了。
第一步,两种从节点的 redis.conf 配置上主节点(主从结构完成):
vi redis.conf
replicaof 主节点ip(192.168.100.138) 6379
cat redis.conf | grep replicaof
注意:对于任何一个从节点,redis-cli 执行
slaveof no one
就可以脱离主从结构了
第二步,三个节点修改 sentinel.conf 配置文件(在redis.conf同级目录下)
vi sentinel.conf 内容如下
daemonize yes
port 26379
protected-mode no
dir "/root/redis-6.0.9/sentinel-tmp"
sentinel monitor redis-master 192.168.100.138 6379 2
sentinel down-after-milliseconds redis-master 30000
sentinel failover-timeout redis-master 180000
sentinel parallel-syncs redis-master 1
然后执行 mkdir /root/redis-6.0.9/sentinel-tmp
sentinel.conf 也并不是要一定和 redis.conf 在同级目录下,只要启动 redis-sentinel 的时候不要指定错了就好了
启动三个redis-server 和 三个 redis-sentinel ,如下(三个机器都要执行)
# 启动中使用 redis.conf 文件
./src/redis-server redis.conf
# 启动中使用 sentinel.conf 文件
./src/redis-sentinel sentinel.conf
启动之后要测试自己的是否搭建好了,验证包括两个方面。
主从结构验证:
测试方法1:info命令 redis集群的任何一个节点,都可以在redis-cli中执行 info replication
测试方法2:在主节点set,然后在两个从节点可以get得到
sentinel生效验证:主节点宕机之后选主(保证高可用),新的节点加入后作为从节点
演示sentinel主持下的选主过程 (主节点上 ./redis-cli --raw 执行里面 shutdown 将主节点挂掉)
主节点(192.168.100.138) 上 ./redis-cli --raw 执行里面 shutdown 将主节点挂掉,仅仅是是去掉停止了 主节点上 redis-server,没有停止主节点上的 redis-sentinel
演示sentinel主持下的从节点加入过程 (刚刚挂掉的主节点再次启动 ./src/redis-server redis.conf)
Java程序连接:有了 sentinel 之后,直接连接sentinel就可以操作redis集群,不用连接实际的redis节点 6379.
因为 sentinel 每个节点都会监控整个redis集群,而且sentinel节点之间还会互相监控,sentinel各个节点之间是平等个关系,redis各个节点节点之间是主从关系。
最后,其实只要连接一个 sentinel 节点就好了,根本不需要连接三个 sentinel 节点,因为一个sentinel节点就已经可以监控 整个 redis 集群了。
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
问题1:Sentinel支持的主从切换过程中会丢失数据,因为只有一个master,slave不可能完整的保证offset和master相同。
问题2:只能单点写,没有解决大数据量,内存存放不下,水平扩容的问题。如果数据量非常大,这时候就要对redis的数据分节点存储了。这个时候需要多个 master-slave 的group,将不同的数据分布到不同的group中。
问题来了,数据如何分片存储?读取的时候如何路由?
Sentinel最重要的的就是故障转移,主节点宕机之后的选主功能,包括:
问题1:什么情况下要选主?
回答1:当主节点挂掉之后要选主。当主挂掉时,在从节点中根据一定策略选出新主,并调整其他从 slaveof 到新主。
问题2:如何选主,到底选哪个slave从节点作为master主节点?
回答2:Redis选主的策略简单来说有三个:
(1)相同条件下,slave 的 priority 设置的越小,优先级越高;
(2)相同条件下,slave 复制的数据越多,优先级越高;
(3)相同条件下,slave 的 进程id 越小,优先级越高;
Redis集群实现Sentinel哨兵应对高可用,完成了。