Redis Sentinel机制与用法(一)

本专栏与Redis相关的文章redis

Redis Sentinel机制与用法(一)
Redis Sentinel机制与用法(二)
Jedis的JedisSentinelPool源代码分析
Jedis的Sharded源代码分析
Redis 主从 Replication 的配置
详解Redis SORT命令
JedisCommand接口说明算法

本文参考翻译自 《Redis Sentinel Documentation》

概述

Redis-Sentinel是Redis官方推荐的高可用性(HA)解决方案,当用Redis作Master-slave的高可用方案时,假如master宕机了,Redis自己(包括它的不少客户端)都没有实现自动进行主备切换,而Redis-sentinel自己也是一个独立运行的进程,它能监控多个master-slave集群,发现master宕机后能进行自懂切换。segmentfault

它的主要功能有如下几点缓存

  • 不时地监控redis是否按照预期良好地运行;
  • 若是发现某个redis节点运行出现情况,可以通知另一个进程(例如它的客户端);
  • 可以进行自动切换。当一个master节点不可用时,可以选举出master的多个slave(若是有超过一个slave的话)中的一个来做为新的master,其它的slave节点会将它所追随的master的地址改成被提高为master的slave的新地址。

<br/>安全

Sentinel支持集群

很显然,只使用单个sentinel进程来监控redis集群是不可靠的,当sentinel进程宕掉后(sentinel自己也有单点问题,single-point-of-failure)整个集群系统将没法按照预期的方式运行。因此有必要将sentinel集群,这样有几个好处:微信

  • 即便有一些sentinel进程宕掉了,依然能够进行redis集群的主备切换;
  • 若是只有一个sentinel进程,若是这个进程运行出错,或者是网络堵塞,那么将没法实现redis集群的主备切换(单点问题);
  • 若是有多个sentinel,redis的客户端能够随意地链接任意一个sentinel来得到关于redis集群中的信息。

Sentinel版本

Sentinel当前最新的稳定版本称为Sentinel 2(与以前的Sentinel 1区分开来)。随着redis2.8的安装包一块儿发行。安装完Redis2.8后,能够在redis2.8/src/里面找到Redis-sentinel的启动程序。网络

强烈建议
若是你使用的是redis2.6(sentinel版本为 sentinel 1),你最好应该使用redis2.8版本的 sentinel 2,由于sentinel 1有不少的Bug,已经被官方弃用,因此强烈建议使用redis2.8以及sentinel 2。

运行Sentinel

运行sentinel有两种方式:并发

  • 第一种异步

    redis-sentinel /path/to/sentinel.conf
  • 第二种spa

    redis-server /path/to/sentinel.conf --sentinel

以上两种方式,都必须指定一个sentinel的配置文件sentinel.conf,若是不指定,将没法启动sentinel。sentinel默认监听26379端口,因此运行前必须肯定该端口没有被别的进程占用。

Sentinel的配置

Redis源码包中包含了一个sentinel.conf文件做为sentinel的配置文件,配置文件自带了关于各个配置项的解释。典型的配置项以下所示:

sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 60000
sentinel failover-timeout mymaster 180000
sentinel parallel-syncs mymaster 1

sentinel monitor resque 192.168.1.3 6380 4
sentinel down-after-milliseconds resque 10000
sentinel failover-timeout resque 180000
sentinel parallel-syncs resque 5

上面的配置项配置了两个名字分别为mymaster和resque的master,配置文件只须要配置master的信息就好啦,不用配置slave的信息,由于slave可以被自动检测到(master节点会有关于slave的消息)。须要注意的是,配置文件在sentinel运行期间是会被动态修改的,例如当发生主备切换时候,配置文件中的master会被修改成另一个slave。这样,以后sentinel若是重启时,就能够根据这个配置来恢复其以前所监控的redis集群的状态。

接下来咱们将一行一行地解释上面的配置项

sentinel monitor mymaster 127.0.0.1 6379 2

这一行表明sentinel监控的master的名字叫作mymaster,地址为127.0.0.1:6379,行尾最后的一个2表明什么意思呢?咱们知道,网络是不可靠的,有时候一个sentinel会由于网络堵塞而误觉得一个master redis已经死掉了,当sentinel集群式,解决这个问题的方法就变得很简单,只须要多个sentinel互相沟通来确认某个master是否真的死了,这个2表明,当集群中有2个sentinel认为master死了时,才能真正认为该master已经不可用了。(sentinel集群中各个sentinel也有互相通讯,经过gossip协议)。

除了第一行配置,咱们发现剩下的配置都有一个统一的格式:

sentinel <option_name> <master_name> <option_value>

接下来咱们根据上面格式中的option_name一个一个来解释这些配置项:

  • down-after-milliseconds

sentinel会向master发送心跳PING来确认master是否存活,若是master在“必定时间范围”内不回应PONG 或者是回复了一个错误消息,那么这个sentinel会主观地(单方面地)认为这个master已经不可用了(subjectively down, 也简称为SDOWN)。而这个down-after-milliseconds就是用来指定这个“必定时间范围”的,单位是毫秒。

不过须要注意的是,这个时候sentinel并不会立刻进行failover主备切换,这个sentinel还须要参考sentinel集群中其余sentinel的意见,若是超过某个数量的sentinel也 主观地认为该master死了,那么这个master就会被 客观地(注意哦,此次不是主观,是客观,与刚才的subjectively down相对,此次是objectively down,简称为ODOWN)认为已经死了。须要一块儿作出决定的sentinel数量在上一条配置中进行配置。
  • parallel-syncs

在发生failover主备切换时,这个选项指定了最多能够有多少个slave同时对新的master进行同步,这个数字越小,完成failover所需的时间就越长,可是若是这个数字越大,就意味着越多的slave由于replication而不可用。能够经过将这个值设为 1 来保证每次只有一个slave处于不能处理命令请求的状态。

其余配置项在sentinel.conf中都有很详细的解释。
全部的配置均可以在运行时用命令SENTINEL SET command动态修改。

Sentinel的“仲裁会”

前面咱们谈到,当一个master被sentinel集群监控时,须要为它指定一个参数,这个参数指定了当须要判决master为不可用,而且进行failover时,所须要的sentinel数量,本文中咱们暂时称这个参数为票数

不过,当failover主备切换真正被触发后,failover并不会立刻进行,还须要sentinel中的大多数sentinel受权后才能够进行failover。
当ODOWN时,failover被触发。failover一旦被触发,尝试去进行failover的sentinel会去得到“大多数”sentinel的受权(若是票数比大多数还要大的时候,则询问更多的sentinel)
这个区别看起来很微妙,可是很容易理解和使用。例如,集群中有5个sentinel,票数被设置为2,当2个sentinel认为一个master已经不可用了之后,将会触发failover,可是,进行failover的那个sentinel必须先得到至少3个sentinel的受权才能够实行failover。
若是票数被设置为5,要达到ODOWN状态,必须全部5个sentinel都主观认为master为不可用,要进行failover,那么得得到全部5个sentinel的受权。

配置版本号

为何要先得到大多数sentinel的承认时才能真正去执行failover呢?

当一个sentinel被受权后,它将会得到宕掉的master的一份最新配置版本号,当failover执行结束之后,这个版本号将会被用于最新的配置。由于大多数sentinel都已经知道该版本号已经被要执行failover的sentinel拿走了,因此其余的sentinel都不能再去使用这个版本号。这意味着,每次failover都会附带有一个独一无二的版本号。咱们将会看到这样作的重要性。

并且,sentinel集群都遵照一个规则:若是sentinel A推荐sentinel B去执行failover,A会等待一段时间后,自行再次去对同一个master执行failover,这个等待的时间是经过failover-timeout配置项去配置的。从这个规则能够看出,sentinel集群中的sentinel不会再同一时刻并发去failover同一个master,第一个进行failover的sentinel若是失败了,另一个将会在必定时间内进行从新进行failover,以此类推。

redis sentinel保证了活跃性:若是大多数sentinel可以互相通讯,最终将会有一个被受权去进行failover.
redis sentinel也保证了安全性:每一个试图去failover同一个master的sentinel都会获得一个独一无二的版本号。

配置传播

一旦一个sentinel成功地对一个master进行了failover,它将会把关于master的最新配置经过广播形式通知其它sentinel,其它的sentinel则更新对应master的配置。

一个faiover要想被成功实行,sentinel必须可以向选为master的slave发送SLAVE OF NO ONE命令,而后可以经过INFO命令看到新master的配置信息。

当将一个slave选举为master并发送SLAVE OF NO ONE`后,即便其它的slave还没针对新master从新配置本身,failover也被认为是成功了的,而后全部sentinels将会发布新的配置信息。

新配在集群中相互传播的方式,就是为何咱们须要当一个sentinel进行failover时必须被受权一个版本号的缘由。

每一个sentinel使用##发布/订阅##的方式持续地传播master的配置版本信息,配置传播的##发布/订阅##管道是:__sentinel__:hello

由于每个配置都有一个版本号,因此以版本号最大的那个为标准。

举个栗子:假设有一个名为mymaster的地址为192.168.1.50:6379。一开始,集群中全部的sentinel都知道这个地址,因而为mymaster的配置打上版本号1。一段时候后mymaster死了,有一个sentinel被受权用版本号2对其进行failover。若是failover成功了,假设地址改成了192.168.1.50:9000,此时配置的版本号为2,进行failover的sentinel会将新配置广播给其余的sentinel,因为其余sentinel维护的版本号为1,发现新配置的版本号为2时,版本号变大了,说明配置更新了,因而就会采用最新的版本号为2的配置。

这意味着sentinel集群保证了第二种活跃性:一个可以互相通讯的sentinel集群最终会采用版本号最高且相同的配置。

SDOWN和ODOWN的更多细节

sentinel对于不可用有两种不一样的见解,一个叫主观不可用(SDOWN),另一个叫客观不可用(ODOWN)。SDOWN是sentinel本身主观上检测到的关于master的状态,ODOWN须要必定数量的sentinel达成一致意见才能认为一个master客观上已经宕掉,各个sentinel之间经过命令SENTINEL is_master_down_by_addr来得到其它sentinel对master的检测结果。

从sentinel的角度来看,若是发送了PING心跳后,在必定时间内没有收到合法的回复,就达到了SDOWN的条件。这个时间在配置中经过is-master-down-after-milliseconds参数配置。

当sentinel发送PING后,如下回复之一都被认为是合法的:

PING replied with +PONG.
PING replied with -LOADING error.
PING replied with -MASTERDOWN error.

其它任何回复(或者根本没有回复)都是不合法的。

从SDOWN切换到ODOWN不须要任何一致性算法,只须要一个gossip协议:若是一个sentinel收到了足够多的sentinel发来消息告诉它某个master已经down掉了,SDOWN状态就会变成ODOWN状态。若是以后master可用了,这个状态就会相应地被清理掉。

正如以前已经解释过了,真正进行failover须要一个受权的过程,可是全部的failover都开始于一个ODOWN状态。

ODOWN状态只适用于master,对于不是master的redis节点sentinel之间不须要任何协商,slaves和sentinel不会有ODOWN状态。

Sentinel之间和Slaves之间的自动发现机制

虽然sentinel集群中各个sentinel都互相链接彼此来检查对方的可用性以及互相发送消息。可是你不用在任何一个sentinel配置任何其它的sentinel的节点。由于sentinel利用了master的发布/订阅机制去自动发现其它也监控了统一master的sentinel节点。

经过向名为__sentinel__:hello的管道中发送消息来实现。

一样,你也不须要在sentinel中配置某个master的全部slave的地址,sentinel会经过询问master来获得这些slave的地址的。

每一个sentinel经过向每一个master和slave的发布/订阅频道__sentinel__:hello每秒发送一次消息,来宣布它的存在。
每一个sentinel也订阅了每一个master和slave的频道__sentinel__:hello的内容,来发现未知的sentinel,当检测到了新的sentinel,则将其加入到自身维护的master监控列表中。
每一个sentinel发送的消息中也包含了其当前维护的最新的master配置。若是某个sentinel发现
本身的配置版本低于接收到的配置版本,则会用新的配置更新本身的master配置。

在为一个master添加一个新的sentinel前,sentinel老是检查是否已经有sentinel与新的sentinel的进程号或者是地址是同样的。若是是那样,这个sentinel将会被删除,而把新的sentinel添加上去。

网络隔离时的一致性

redis sentinel集群的配置的一致性模型为最终一致性,集群中每一个sentinel最终都会采用最高版本的配置。然而,在实际的应用环境中,有三个不一样的角色会与sentinel打交道:

  • Redis实例.
  • Sentinel实例.
  • 客户端.

为了考察整个系统的行为咱们必须同时考虑到这三个角色。

下面有个简单的例子,有三个主机,每一个主机分别运行一个redis和一个sentinel:

+-------------+
             | Sentinel 1  | <--- Client A
             | Redis 1 (M) |
             +-------------+
                     |
                     |
 +-------------+     |                     +------------+
 | Sentinel 2  |-----+-- / partition / ----| Sentinel 3 | <--- Client B
 | Redis 2 (S) |                           | Redis 3 (M)|
 +-------------+                           +------------+

在这个系统中,初始状态下redis3是master, redis1和redis2是slave。以后redis3所在的主机网络不可用了,sentinel1和sentinel2启动了failover并把redis1选举为master。

Sentinel集群的特性保证了sentinel1和sentinel2获得了关于master的最新配置。可是sentinel3依然持着的是就的配置,由于它与外界隔离了。

当网络恢复之后,咱们知道sentinel3将会更新它的配置。可是,若是客户端所链接的master被网络隔离,会发生什么呢?

客户端将依然能够向redis3写数据,可是当网络恢复后,redis3就会变成redis的一个slave,那么,在网络隔离期间,客户端向redis3写的数据将会丢失。

也许你不会但愿这个场景发生:

  • 若是你把redis当作缓存来使用,那么你也许能容忍这部分数据的丢失。
  • 但若是你把redis当作一个存储系统来使用,你也许就没法容忍这部分数据的丢失了。

由于redis采用的是异步复制,在这样的场景下,没有办法避免数据的丢失。然而,你能够经过如下配置来配置redis3和redis1,使得数据不会丢失。

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

经过上面的配置,当一个redis是master时,若是它不能向至少一个slave写数据(上面的min-slaves-to-write指定了slave的数量),它将会拒绝接受客户端的写请求。因为复制是异步的,master没法向slave写数据意味着slave要么断开链接了,要么不在指定时间内向master发送同步数据的请求了(上面的min-slaves-max-lag指定了这个时间)。

Sentinel状态持久化

snetinel的状态会被持久化地写入sentinel的配置文件中。每次当收到一个新的配置时,或者新建立一个配置时,配置会被持久化到硬盘中,并带上配置的版本戳。这意味着,能够安全的中止和重启sentinel进程。

扫一扫关注个人微信公众号