在了解哨兵机制前先来了解一下主从复制。在实际的应用过程中常常会遇到一些高并发高数据量的场景,对缓存提出了高可用性高稳定的需求,然而在只有单个redis服务器时,单台redis服务器需要处理所有的请求负载,压力大,容错性低,一旦出现故障会导致所有请求被送到持久层数据库。此外,单个Redis虽然容量为256G,但并不能将所有内容都用作Redis存储内存,一般情况下单台Redis最大使用的内存不应超过20G。对此解决办法是使用多台Redis服务器。
主从复制即将多台Redis服务器分为一台主服务器(master)和多台从服务器(slave),其中主服务器负责写操作,从服务器负责读操作,主服务器会定期将数据同步到从服务器中保证数据的一致性。
即将主服务器中的全部数据都发送给从服务器,是一个非常重型的操作,当数据量很大时会对主从节点和网络造成很呆的开销。通常应用于初始化slave或其他无法进行增量同步的情况。
全量同步的过程:
从服务器连接主服务器,发送SYNC命令
主服务器收到命令后开始执行BGSAVE命令生成RDB文件并使用缓冲区记录此后执行的所有命令
主服务器执行完层BGSAVE后,向从数据库发送快照文件,并在发送期间继续记录被执行的命令
从服务器收到快照文件后丢弃所有旧数据,载入收到的快照文件
从服务器完成对快照的载入,开始接受命令请求,并执行来自主服务器的缓冲区的写命令
增量同步是指slave初始化后开始正常工作时主服务器发生写操作时同步到从服务器的过程。通常情况下主服务器每执行一个写命令就会向从服务器发送相同的写命令,从服务器接受并执行
首先拷贝一份配置文件作为从服务器的配置文件
然后更改配置文件,更改port属性,可以改成6380
添加slaveof配置,说明该从服务器对应的主服务器的IP和port,当然这句话也可以放在启动时在命令行中输入
启动后可以通过info replication命令查看从服务器的状态以及所属服务器
可以看到在从服务器想要写入数据是失败的
虽然主从复制可以很好的解决高并发高性能的需求,但仍然存在这样一个问题:如果Master出现问题怎么办?出于这样的原因引入了哨兵机制
什么哨兵呢?在现实生活我们常常能在军营门口看到哨兵,哨兵的任务是站岗,监测大门口的状况,及时发现异常状况,redis中的哨兵也同样肩负着这样的职责。
哨兵(Sentinel)是一个独立的进程,其通过发送命令等待redis服务器响应,从而监控各个Redis服务器的状态,并在master出现故障时切换新的master。在一个架构中可以使用多个哨兵进程
哨兵会不断的检查Master和Slave是否运行正常.
当被监控的某个redis节点出现问题时,哨兵可以通过API向管理员或其他应用程序发送通知
当一个主服务器被哨兵视为客观下线时,该哨兵会和其他哨兵协商选出领头哨兵进行故障转移工作。
在一个集群中的哨兵之间是知到互相的存在的,但在配置哨兵的配置文件时,只需要配置哨兵需要监控的主节点的信息即可,而不用配置其他哨兵的信息。这是因为哨兵之间会通过订阅发布机制来进行自动发现。
每个哨兵都会订阅它所监控的主服务器和从服务器的_sentinel_:hello频道,哨兵会以每两秒一次的频率向该频道中发送一条信息,包含了哨兵的ip地址、端口和运行ID。当一个哨兵发现了一个新的哨兵发出的消息时,它会检验维护已知哨兵的列表中是否存在拥有相同运行ID或相同地址的哨兵,若有,则该哨兵会先移除列表中已有的相同运行ID或相同地址的哨兵,然后添加新的哨兵,若没有则直接将新的哨兵添加到已知Sentinel的列表中。
此外哨兵发送的消息中还包含完整的主服务器的配置信息,若一个哨兵的主服务器配置信息旧于另一个哨兵发送的配置信息,那么该哨兵会升级到新的配置。
哨兵会以每秒一次的频率向集群中的主服务器和从服务器发送ping命令,若在down-after-milliseseconds时间内ping连接无效,则将该服务器视为主观下线(主观下线即单个哨兵节点对redis节点视为下线)之后该哨兵节点会询问其他一同监控同一主服务器的哨兵节点是否也将该服务器视为主观下线,若判定该服务器为主观下线的哨兵节点数量超过了quorum后将会视其为客观下线。
(这一块不是很详细,深入理解后再重新整理)
当集群中主节点被认为客观下线时,需要在Sentinel中选举出Leader,由它来负责故障转移工作。当故障转移工作完成后所有Sentinel又会恢复到平等的地位。
选举流程:
(1)若某个Sentinel认定master客观下线,该Sentinel会先查看自己有没有投过票,若自己已经投票给其他Sentinel了,则在两倍故障转移的超时时间自己就不会 称为Leader,即它已经成为了Follower
(2)若该Sentinel还没有投过票,它就会成为Candidate
(3)成为Candidate后会向其他节点发送is-master-down-by-addr命令请求投票
(4)收到is-master-down-by-addr命令的Sentinel会检查自己是否已经投票,若已经投过票,则不再参与投票,若没有参与投票,则将票投给发送该命令的Candidate
(5)Candidate会不断统计自己的票数,若认同该Candidate成为Leader的票数超过一半且超过配置文件中设置的quorum,则该Sentinel成为Leader
(6)若在一个选举时间内,Candidate没有获得超过一半且超过quorum的票数,则竞选失败
(7)若在一个选举时间内,没有一个Candidate获得更多的票数,则等待超过两倍故障转移时间后重新投票
在选举出Leader后,Leader就会对已下线的主服务器进行故障转移操作。Leader会咋子已下线的主服务器中的所有从服务器中挑选出一个从服务器,将其转换为主服务器,然后已下线的主服务器的所有从服务器都会改为复制新的主服务器,并将已下线的主服务器设置为新的主服务器的从服务器,当这个旧主服务器重新上线时就会自动称为新的主服务器的从服务器
选取新的master的依据:
(1)排除断线的从服务器
(2)选择优先级最高的从服务器
(3)若从服务器优先级相同,选择复制偏移量最大的从服务器
(4)若偏移量相同,选择运行ID最小的从服务器
首先我们搭建一个一主二从的redis集群。主服务器的端口为6379,从服务器的端口分别为6380和6381,拓扑关系如下
对这个集群建立包含三个sentinel的哨兵集群来对服务器进行监控,sentinel的端口分别为26379、26380和26381,拓扑关系如下
将redis下载文件的解压包中的sentinel.conf文件复制成三分,放在redis的安装目录下,分别作为三个sentinel的配置文件,对配置文件进行修改,其中比较重要的是以下几个配置:
sentinel monitor
sentinel down-after-milliseconds
daemonize,指明该Sentinel是否以守护进程运行
logfile,指明日志打印的文件
其他配置可以不用改
开启redis集群和三个哨兵后的进程如下
通过redis-cli连接哨兵后使用 info sentinel命令查看一个哨兵的状态,可以看到哨兵正在监控127.0.0.1:6379,同时也发现了集群中的两个从服务器和其他两个哨兵
通过redis-cli连接主服务器和从服务器后通过info replication命令查看主从服务器的连接情况
主服务器,可以看到,已有两个服务器连接
6380:
此时进入主服务器6379执行shutdown命令,关闭主服务器
这时候我们查看其中一个哨兵的日志,发现该哨兵在主服务器关闭后首先认定主服务器为sdown状态(即主观下线),当认定master为主观下线的哨兵数量达到quorum(此处为2)时,判定主节点为odown状态(即客观下线)
选举Leader
选择6381成为新的master
最后将6381转换为新的master,并让6379和6380称为6381的从节点
此时再来查看6381的主从关系,发现6381已经成为了主服务器,并且有一个从服务器连接
查看6380的主从状态,此时它的主服务器也变成了6381
当重新启动6379节点时,我们在来查看6381的主传动状态,发现有两个从节点,显然重新上线的6379自动成为了它的从节点