Redis哨兵模式相关知识

1.简介

哨兵是redis集群架构中非常重要的一个组件,哨兵模式基于主从复制模式,当主从复制模式下的master主节点宕机,通过选举一个master继续提供服务;


2.功能

1>.集群监控: 负责监控redis master和slave进程是否正常工作;
2>.消息通知: 如果某个redis实例有故障,那么哨兵负责发送消息作为报警通知给管理员;
3>.故障转移: 如果master node挂掉了,会自动转移到slave node上,会选举一个slave node作为新的master node,让其他的slave node重新连接到新选出的master node;
4>.配置中心: 如果故障转移发生了(/选举了新的master),通知client客户端新的master地址


3.特点

哨兵本身也是分布式的,作为一个哨兵集群去运行,相互协调工作

1>.故障转移时,判断一个master node宕机了,需要大部分的哨兵(节点)都同意才行,这就涉及到了分布式选举问题;

2>.即使部分哨兵节点挂掉了,哨兵集群中剩下的节点还是可以正常工作的,因为如果作为高可用机制的一个重要组成部分,故障转移系统本身是单点的,那就太坑了;

3>.目前采用的是sentinel 2版本(对于redis3.0以上版本),相对于sentinel 1版本来说,sentinel 2版本重写了很多代码,主要是让故障转移机制和算法变得更加健壮和简单;


4.核心知识

1>.哨兵至少需要3个实例(/节点)来保证自己的健壮性;
2>.[哨兵 + redis主从]的部署架构,是不能保证数据零丢失的,只能保证redis集群的高可用性;
3>.对于[哨兵+redis主从]这种复杂的部署架构,尽量在测试环境和生产环境都进行充足的测试和演练;


5.为什么redis哨兵集群需要3个节点才能正常工作?

1>.哨兵集群在进行redis故障判断,主备切换的时候需要配置一个参数(qurum),这个参数表示有多少个哨兵节点一致认为master node宕机了(master node状态从sdown变成odown),就可以准备进行主备切换,之后会选出一个新的master node准备故障转移,同时还需要majority数量,也就是集群中大多数哨兵都是运行的,得到majority大多数哨兵的授权,才能正式进行主备切换;


5.1.quorum和majority参数

  • quorum:至少需要多少个哨兵节点一致认为master node宕机(master node状态变成odown),才能允许进行主备切换;
  • majority:至少需要多少个哨兵节点授权(/存活),才能正式进行主备切换;
  • majority=n/2+1; quorum=n-1,(0

1>.每次一个哨兵节点要做主备切换,首先需要quorum数量的哨兵认为master node宕机了,然后选举出一个哨兵来做切换,这个哨兵还得得到majority数量的哨兵的授权,才能正式执行切换

①.如果quorum < majority,比如5个哨兵,majority就是3,quorum设置为2,那么就3个哨兵授权就可以执行切换;

②.如果quorum >= majority,那么必须quorum数量的哨兵都授权,比如5个哨兵,quorum是5,那么必须5个哨兵都同意授权,才能执行切换;

  • 2个哨兵节点的majority=2;

  • 3个哨兵节点的majority=2;

  • 4个哨兵节点的majority=3;

  • 5个哨兵节点的majority=3;

③.假设集群中只有2个节点,quorum=1,majority=2,如果一个节点宕机了,另外一个哨兵准备故障转移/主备切换,但是无法满足majority=2,无法进行真正的故障转移/主备切换;

④.假设集群中只有3个节点,quorum=2,majority=2,如果一个节点宕机了,另外两个哨兵选出一个其中一个哨兵准备故障转移/主备切换,而此时可以满足majority=2,那么就可以进行正式切换;

所以,哨兵集群中至少需要三个实例才能正常工作!!!


6.Redis哨兵主备切换的数据丢失问题

6.1.异步复制导致数据丢失

因为master–>slave的复制是异步的,所以有可能有部分数据还没有复制到slave,master就宕机了,那么这部分还没有复制过去的数据就丢失了;当故障转移/主备切换之后,client所有的写请求,都会基于这个新的master node,那么之前旧的master node内存中那些还没来得及复制到slave node中的数据就丢失了;


6.2.集群脑裂导致数据丢失

1>.脑裂,也就是说,某个master node所在的机器突然脱离了正常的网络,跟其他的slave node暂时失联了(但是实际上该master node还活着),此时其他的哨兵可能会认为master node已经宕机了,然后开始选举,将某个slave node切换成master node进行故障转移,这个时候集群就会有两个master node,这就是所谓的脑裂;

2>.此时虽然经过故障转移将某个slave node切换成了master node,但是有可能client客户端还没来得及切换到新的master node,有可能还继续和之前的那个master 进行通信(写入操作),当之前旧的master node所在机器网络恢复之后,该master node就会作为一个slave node挂载到后来选举出来的新的master node上,然后清空自己的数据,重新从新的master node上去同步数据,那么在故障期间client写入(到出现网络故障master node)的数据就丢失了;


6.3.解决异步复制和脑裂导致的数据丢失

1>.在集群所有的节点配置文件中添加以下配置:

min-slaves-to-write 1
min-slaves-max-lag 10


上面两个配置意思是说,要求至少有1个slave,数据复制和同步的延迟不能超过10秒;如果一旦所有的slave,数据复制和同步的延迟都超过了10秒钟,那么这个时候,master就不会再接收任何请求了,可以减少异步复制和脑裂导致的数据丢失


6.3.1.减少异步复制的数据丢失

有了min-slaves-max-lag这个配置,就可以确保一旦slave复制数据速度太慢和ack延时太长,导致与master node上的数据相差/落后太多(超过10s),那么就认为可能master宕机后丢失的数据太多了,那么master node就会拒绝client写请求,然后client就把要写入的数据(/写入的指令)暂时缓存到自己内存中,然后再尝试写入到其他的master node或者直接停顿一段时间(等到master 和 slave node数据同步之后)然后在写[一般来说会在client做降级/限流处理,先将数据写入到磁盘中,然后对外减慢请求涌入速度;或者在client端将数据临时灌入一个kafka消息队列中每隔10分钟去队列中取出数据发回master],这样可以把master宕机时未同步到slave丢失数据降低到可控范围内;


6.3.2.减少集群脑裂的数据丢失

1>.如果一个master出现了脑裂,跟其他slave丢了连接,那么上面两个配置可以确保,如果不能继续给指定数量的slave发送数据,而且slave超过10秒没有给自己返回ack消息,那么就直接拒绝客户端的写请求;这样脑裂后的旧master就不会接受client的新数据,也就避免了数据丢失;

2>.上面的配置就确保了,如果跟任何一个slave丢了连接,在10秒后发现没有slave给自己返回ack,那么就拒绝client新的写请求[采取上面的client端降级/限流处理方案];因此在脑裂场景下,最多就丢失10秒的数据;


7.哨兵的多个核心底层原理的深入理解

7.1.sdown和odown转换机制

  • sdown是主观宕机,就是一个哨兵如果自己觉得一个master宕机了,那么就是主观宕机;
  • odown是客观宕机,如果quorum数量的哨兵节点都觉得某一个master宕机了,那么就是客观宕机;
  • 客观=quorum数量的主观

1>.sdown达成的条件很简单,如果一个哨兵ping一个master,超过了is-master-down-after-milliseconds指定的毫秒数之后,就主观认为master宕机;

2>.sdown到odown转换的条件很简单,如果一个哨兵在指定时间内,收到了quorum数量的其他哨兵也认为master是sdown了的消息/通知,那么所有的哨兵转换成是odown了,客观认为master宕机;


7.2.哨兵集群的自动发现机制

1>.哨兵互相之间的发现是通过redis的pub/sub(发布订阅)系统实现的,每个哨兵都会往__sentinel__:hello这个channel通道里发送一个消息,这时候由于所有哨兵都订阅了这个消息,那么其他哨兵都可以消费到这个消息,每个哨兵并感知到其他的哨兵的存在;

2>.每隔两秒钟,每个哨兵都会往自己监控的某个master+slaves集群对应的__sentinel__:hello的channel通道里发送一个消息,内容是自己的host、ip和runid还有对这个master的监控配置;

3>.每个哨兵也会去监听自己监控的每个master+slaves对应的__sentinel__:hello 的channel,然后去感知同样也在监听这个master+slaves集群对应通道的其他哨兵的存在;

4>.每个哨兵还会通过这个pub/sub(发布订阅)系统跟其他哨兵交换对master的监控配置,互相进行监控配置的同步;


7.3.slave配置的自动纠正

哨兵会负责自动纠正slave的一些配置,比如slave如果要成为潜在的master候选人,哨兵会确保slave在复制现有master的数据,如果slave连接到了一个错误的master上,比如故障转移之后,那么哨兵会确保它们连接到正确的master上;


7.4.slave到master选举算法

1>.如果一个master被认为odown客观宕机了,而且majority数量的哨兵都允许了主备切换,那么某个哨兵就会执行主备切换操作,此时首先要选举一个slave来准备故障转移;

2>.(选举算法)选举slave时会考虑的一些因素:

①.跟master断开连接的时长;
②.slave优先级;
③.复制offset;
④.run id

3>.如果一个slave跟master断开连接已经超过了(down-after-milliseconds的10倍外加master宕机的时长),那么这个slave就被认为不适合选举为master;

(down-after-milliseconds * 10) +milliseconds_since_master_is_in_SDOWN_state

4>.然后会对每个slave进行排序:

①.按照slave优先级进行排序,slave priority值越小,优先级就越高;
②.如果slave priority值相同,那么看replica offset,哪个slave的offset越靠后(大),那么就表示哪个slave复制了越多的数据,他的优先级就越高;
③.如果上面两个条件都相同,那么选择run id比较小的那个slave来为故障转移做准备


7.5.configuration epoch

1>.哨兵会对一套redis的[master+slave]集群进行监控,有相应的监控的配置;

2>.执行切换的那个哨兵,在切换之前会从要切换到的新master(salve->master)那里得到一个configuration epoch,这就是一个version号,每次切换的version号都必须是唯一的;

3>.如果第一个选举出的哨兵切换失败了,那么第二个哨兵会等待failover-timeout时间,然后接替(第一个选举出的哨兵)继续执行切换,此时会重新获取一个新的configuration epoch,作为新的version号;


7.6.configuraiton传播

1>.哨兵完成切换之后,会在自己本地更新生成最新的master配置,然后同步给其他的哨兵,就是通过之前说的pub/sub(发布/订阅)消息机制;

2>.这里新的master的version号就很重要了,因为各种消息都是通过一个channel去发布和监听的,所以一个哨兵完成一次新的切换之后,新的master配置是跟着新的version号的;

3>.其他的哨兵都是根据版本号的大小来更新自己的master配置的;


8.在项目中以经典的3个节点方式部署哨兵集群

注意:哨兵模式是基于主从复制(一主多从)模式,所以先要配置主从复制

8.1.哨兵配置[三台机器]

1>.安装redis-3.2.8,配置主从复制

2>.sentinel哨兵配置

①.创建一个存放哨兵配置文件的文件夹

# mkdir -p /etc/sentinal/config

②.创建存放哨兵数据文件的文件夹

# mkdir -p /var/sentinal/data
# mkdir -p /var/sentinal/log

③.创建哨兵配置文件sentinel.conf

# cd /etc/sentinal/config
# vim sentinel.conf

④添加如下内容:

port 5000                     
bind 0.0.0.0                 
dir /var/sentinal/data
sentinel monitor mymaster 192.168.1.121 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1
daemonize yes
logfile /var/sentinal/log/sentinel.log

//参数说明:

  • port [xxx] //哨兵端口,默认26379,不能跟其他机器在指定端口连通;只能在本地访问;所有节点保持一致!!
  • bind [xxx] //哨兵集群中每个(当前)节点/服务器IP地址,保持唯一!
  • dir [xxx] //指定哨兵数据文件存放目录;所有节点保持一致!!
  • sentinel monitor [master-group-name] [hostname/ip] [port] [quorum] //哨兵集群中master节点的组名称(随便取),IP地址,当前redis端口,quorum值;所有节点保持一致!!
  • sentinel down-after-milliseconds [master-group-name] [xxx] //超过多少毫秒跟一个指定的redis实例(master)断了连接,哨兵就可能认为这个redis实例挂了;所有节点保持一致!!
  • sentinel failover-timeout [master-group-name] [xxx] //执行故障转移的timeout超时时长;所有节点保持一致!!
  • sentinel parallel-syncs [master-group-name] [xxx] //新的master被切换之后,同时有多少个slave被切换到去连接新master,重新做同步,数字越低,花费的时间越多;但是如果这个数字越大,就意味着越多的slave因为replication而不可用;所有节点保持一致!!
  • daemonize //指定哨兵以守护进程/后台方式启动,这样就不会占用命令行窗口;所有节点保持一致!!
  • logfile //指定哨兵日志文件存放目录;所有节点保持一致!!

8.2.启动哨兵进程[三台机器]

1>.先启动集群各个节点的redis服务

# cd /etc/init.d/
# ./redis_6379 start

2>.通过redis-sentinel脚本执行sentinel进程

# redis-sentinel /etc/sentinal/sentinel.conf

//启动示意图如下:
Redis哨兵模式相关知识_第1张图片
说明:

①.根据提示信息,每个节点除了监控master节点之外还监控着其他哨兵节点!
②.哨兵之间,互相会自动进行发现,用的就是之前说的pub/sub,消息发布和订阅channel消息系统和机制;


8.3.检查哨兵状态

1>.链接任意一个哨兵节点

# redis-cli -h 192.168.1.121 -p 5000

2>.执行哨兵相关的命令

> SENTINEL master mymaster       //查看master节点信息
> SENTINEL slaves mymaster       //查看(当前)slave节点信息
> SENTINEL sentinels mymaster   //查看所有的非master哨兵节点信息
> SENTINEL get-master-addr-by-name mymaster  //查看master节点信息

9.对项目中的哨兵节点进行管理以及高可用redis集群演练

9.1.哨兵节点的增加

增加一台服务器,按照上面步骤进行配置即可,集群会自动发现新加入的哨兵节点;


9.2.剔除一个哨兵节点

1>.停止要剔除的哨兵节点的sentinal进程

2>.在其他所有sentinal哨兵节点上执行清理所有的master状态

> SENTINEL RESET *

3>.在所有sentinal哨兵节点上执行查看所有sentinal对数量是否达成了一致

> SENTINEL master mymaster

9.3.slave的永久下线(让master摘除某个已经下线的slave)

1>.在其他所有的哨兵上面执行重置master信息/状态

> SENTINEL RESET <mastername>

9.4.容灾演练

1>.通过哨兵看一下当前的master

> SENTINEL get-master-addr-by-name mymaster

2>.把master节点的redis服务关掉(sentinel服务不要关),删除对应的pid文件

3>.查看其他哨兵节点的sentinal命令行窗口的日志,是否出现+sdown...的字样,然后出现+odown...的字样,就是指定的quorum数量个哨兵都认为master宕机了
Redis哨兵模式相关知识_第2张图片
Redis哨兵模式相关知识_第3张图片
Redis哨兵模式相关知识_第4张图片

主备切换具体流程说明:

①.三个哨兵进程都认为master是sdown了;
②.超过quorum指定的哨兵进程都认为sdown之后,就变为odown;
③.哨兵2是被选举为要执行后续的主备切换的那个哨兵;
④.哨兵2去新的master(slave)获取了一个新的config version;
⑤.尝试执行failover故障转移;
⑥.投票选举出一个slave被切换成master,每个哨兵都会执行一次投票;
⑦.让选举出来的这个slave执行slaveof no one,不让它去做任何节点的slave了; 把slave提拔成master;各节点认为旧的master不再是master了;
⑧.哨兵就自动认为之前的master变成了slave了,新选出来的slave变成了master了;
⑨.哨兵去探查了一下之前的master这个salve的状态,认为它sdown了;

4>.在任意一个节点上查看master信息
在这里插入图片描述
5>.查看各节点哨兵的配置文件,发现master由之前的"121"自动变成了"122"
Redis哨兵模式相关知识_第5张图片
6>.redis客户端链接到新的master节点,执行读写操作
Redis哨兵模式相关知识_第6张图片
7>.再看其他节点上的数据
在这里插入图片描述
//数据已经同步了!

8>.查看主从架构信息
Redis哨兵模式相关知识_第7张图片
9>.旧的master(121)重新启动,查看是否被哨兵自动切换成slave节点
Redis哨兵模式相关知识_第8张图片
在这里插入图片描述
//旧的master启动之后,哨兵将他变成了slave,挂在新的master上!

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