Redis Sentinel实现的机制与原理详解

序言

Redis-Sentinel是Redis官方推荐的高可用性(HA)解决方案。实际上这意味着你可使用Sentinel模式建立一个能够不用人为干预而应对各类故障的Redis部署。html

它的主要功能有如下几点正则表达式

  • 监控:Sentinel不断的检查master和slave是否正常的运行。redis

  • 通知:若是发现某个redis节点运行出现问题,能够经过API通知系统管理员和其余的应用程序。算法

  • 自动故障转移:可以进行自动切换。当一个master节点不可用时,可以选举出master的多个slave中的一个来做为新的master,其它的slave节点会将它所追随的master的地址改成被提高为master的slave的新地址。segmentfault

  • 配置提供者:哨兵做为Redis客户端发现的权威来源:客户端链接到哨兵请求当前可靠的master的地址。若是发生故障,哨兵将报告新地址。缓存

sentinel的分布式特性

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

  • 即便有一些sentinel进程宕掉了,依然能够进行redis集群的主备切换;ruby

  • 若是只有一个sentinel进程,若是这个进程运行出错,或者是网络堵塞,那么将没法实现redis集群的主备切换(单点问题);网络

  • 若是有多个sentinel,redis的客户端能够随意地链接任意一个sentinel来得到关于redis集群中的信息。并发

关于sentinel的稳定版本

当前的哨兵版本是sentinel 2。它是基于最初哨兵的实现,使用更健壮的和更简单的预算算法(在这个文档里有解释)重写的。

Redis2.8和Redis3.0附带稳定的哨兵版本。他们是Redis的两个最新稳定版本。

在不稳定版本的分支上执行新的改进,且有时一些新特性一旦被认为是稳定的就会被移植到Redis2.8和Redis3.0分支中。

Redis2.6附带Redis sentinel 1,它是弃用的不建议使用。

运行sentinel

运行Sentinel有两种方式,以下:

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

两种方式效果都是同样的。

然而在启动哨兵时必须使用一个配置文件,由于这个配置文件将用于系统保存当前状态和在重启时从新加载。哨兵会在没有指定配置文件或指定的配置文件不可写的时候拒绝启动。

Redis 哨兵默认监听26379 TCP端口,因此为了哨兵的正常工做,你的26379端口必须开放接收其余哨兵实例的IP地址的链接。不然哨兵不能通讯和商定作什么,故障转移将永不会执行。

部署哨兵以前须要了解的基本事情

  1. 一个健壮的部署至少须要三个哨兵实例。

  2. 三个哨兵实例应该放置在客户使用独立方式确认故障的计算机或虚拟机中。例如不一样的物理机或不一样可用区域的虚拟机。

  3. sentinel + Redis实例不保证在故障期间保留确认的写入,由于Redis使用异步复制。然而有方式部署哨兵使丢失数据限制在特定时刻,虽然有更安全的方式部署它。

  4. 你的客户端要支持哨兵,流行的客户端都支持哨兵,但不是所有。

  5. 没有HA设置是安全的,若是你不常常的在开发环境测试,在生产环境他们会更好。你可能会有一个明显的错误配置只是当太晚的时候。

  6. Sentinel,Docker,或者其余形式的网络地址交换或端口映射须要加倍当心:Docker执行端口从新映射,破坏Sentinel自动发现其余的哨兵进程和master的slave列表。稍后在这个文档里检查关于Sentinel和Docker的部分,了解更多信息。

Sentinel的配置

Redis源码发布包包含一个sentinel.conf的文件,默认的配置文件中有关于各个配置项的详细解释,一个典型的最小的配置文件就像下面的配置:

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 monitor [master-group-name] [ip] [port] [quorum]

master-group-name:master名称

quorun:本文叫作票数,Sentinel须要协商赞成master是否可到达的数量。

sentinel monitor mymaster 127.0.0.1 6379 2

这一行用于告诉Redis监控一个master叫作mymaster,它的地址在127.0.0.1,端口为6379,票数是2。

这里的票数须要解释下:举个栗子,redis集群中有5个sentinel实例,其中master挂掉啦,若是这里的票数是2,表示有2个sentinel认为master挂掉啦,才能被认为是正真的挂掉啦。其中sentinel集群中各个sentinel也有互相通讯,经过gossip协议。

除啦第一行其余的格式以下:

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

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

Sentinel的“仲裁会”

前面咱们谈到,主从故障转移时,须要的sentinel承认的票数达到设置的值才能够。

不过,当failover主备切换真正被触发后,failover并不会立刻进行,还须要sentinel中的大多数sentinel受权后才能够进行failover。
当sentinel承认不可用的票数达到时(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,B会等待一段时间后,自行再次去对同一个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进程。

无failover时的配置纠正

即便当前没有failover正在进行,sentinel依然会使用当前配置去设置监控的master。特别是:

  • 根据最新配置确认为slaves的节点却声称本身是master(参考上文例子中被网络隔离后的的redis3),这时它们会被从新配置为当前master的slave。

  • 若是slaves链接了一个错误的master,将会被改正过来,链接到正确的master。

Slave选举与优先级

当一个sentinel准备好了要进行failover,而且收到了其余sentinel的受权,那么就须要选举出一个合适的slave来作为新的master。

slave的选举主要会评估slave的如下几个方面:

  • 与master断开链接的次数

  • Slave的优先级

  • 数据复制的下标(用来评估slave当前拥有多少master的数据)

  • 进程ID

若是一个slave与master失去联系超过10次,而且每次都超过了配置的最大失联时间(down-after-milliseconds option),而且,若是sentinel在进行failover时发现slave失联,那么这个slave就会被sentinel认为不适合用来作新master的。

更严格的定义是,若是一个slave持续断开链接的时间超过

(down-after-milliseconds * 10) + milliseconds_since_master_is_in_SDOWN_state

就会被认为失去选举资格。符合上述条件的slave才会被列入master候选人列表,并根据如下顺序来进行排序:

  1. sentinel首先会根据slaves的优先级来进行排序,优先级越小排名越靠前(?)。

  2. 若是优先级相同,则查看复制的下标,哪一个从master接收的复制数据多,哪一个就靠前。

  3. 若是优先级和下标都相同,就选择进程ID较小的那个。

一个redis不管是master仍是slave,都必须在配置中指定一个slave优先级。要注意到master也是有可能经过failover变成slave的。

若是一个redis的slave优先级配置为0,那么它将永远不会被选为master。可是它依然会从master哪里复制数据。

Sentinel和Redis身份验证

当一个master配置为须要密码才能链接时,客户端和slave在链接时都须要提供密码。

master经过requirepass设置自身的密码,不提供密码没法链接到这个master。
slave经过masterauth来设置访问master时的密码。

可是当使用了sentinel时,因为一个master可能会变成一个slave,一个slave也可能会变成master,因此须要同时设置上述两个配置项。

Sentinel API

Sentinel默认运行在26379端口上,sentinel支持redis协议,因此可使用redis-cli客户端或者其余可用的客户端来与sentinel通讯。

有两种方式可以与sentinel通讯:

  • 一种是直接使用客户端向它发消息

  • 另一种是使用发布/订阅模式来订阅sentinel事件,好比说failover,或者某个redis实例运行出错,等等。

Sentinel命令

sentinel支持的合法命令以下:

  • PING sentinel回复PONG.

  • SENTINEL masters 显示被监控的全部master以及它们的状态.

  • SENTINEL master <master name> 显示指定master的信息和状态;

  • SENTINEL slaves <master name> 显示指定master的全部slave以及它们的状态;

  • SENTINEL get-master-addr-by-name <master name> 返回指定master的ip和端口,若是正在进行failover或者failover已经完成,将会显示被提高为master的slave的ip和端口。

  • SENTINEL reset <pattern> 重置名字匹配该正则表达式的全部的master的状态信息,清楚其以前的状态信息,以及slaves信息。

  • SENTINEL failover <master name> 强制sentinel执行failover,而且不须要获得其余sentinel的赞成。可是failover后会将最新

动态修改Sentinel配置

从redis2.8.4开始,sentinel提供了一组API用来添加,删除,修改master的配置。

须要注意的是,若是你经过API修改了一个sentinel的配置,sentinel不会把修改的配置告诉其余sentinel。你须要本身手动地对多个sentinel发送修改配置的命令。

如下是一些修改sentinel配置的命令:

  • SENTINEL MONITOR <name> <ip> <port> <quorum> 这个命令告诉sentinel去监听一个新的master

  • SENTINEL REMOVE <name> 命令sentinel放弃对某个master的监听

  • SENTINEL SET <name> <option> <value> 这个命令很像Redis的CONFIG SET命令,用来改变指定master的配置。支持多个<option><value>。例如如下实例:

  • SENTINEL SET objects-cache-master down-after-milliseconds 1000

只要是配置文件中存在的配置项,均可以用SENTINEL SET命令来设置。这个还能够用来设置master的属性,好比说quorum(票数),而不须要先删除master,再从新添加master。例如:

SENTINEL SET objects-cache-master quorum 5

增长或删除Sentinel

因为有sentinel自动发现机制,因此添加一个sentinel到你的集群中很是容易,你所须要作的只是监控到某个Master上,而后新添加的sentinel就能得到其余sentinel的信息以及masterd全部的slave。

若是你须要添加多个sentinel,建议你一个接着一个添加,这样能够预防网络隔离带来的问题。你能够每一个30秒添加一个sentinel。最后你能够用SENTINEL MASTER mastername来检查一下是否全部的sentinel都已经监控到了master。

删除一个sentinel显得有点复杂:由于sentinel永远不会删除一个已经存在过的sentinel,即便它已经与组织失去联系好久了。要想删除一个sentinel,应该遵循以下步骤:

  1. 中止所要删除的sentinel

  2. 发送一个SENTINEL RESET * 命令给全部其它的sentinel实例,若是你想要重置指定master上面的sentinel,只须要把*号改成特定的名字,注意,须要一个接一个发,每次发送的间隔不低于30秒。

  3. 检查一下全部的sentinels是否都有一致的当前sentinel数。使用SENTINEL MASTER mastername 来查询。

删除旧master或者不可达slave

sentinel永远会记录好一个Master的slaves,即便slave已经与组织失联很久了。这是颇有用的,由于sentinel集群必须有能力把一个恢复可用的slave进行从新配置。

而且,failover后,失效的master将会被标记为新master的一个slave,这样的话,当它变得可用时,就会重新master上复制数据。

而后,有时候你想要永久地删除掉一个slave(有可能它曾经是个master),你只须要发送一个SENTINEL RESET master命令给全部的sentinels,它们将会更新列表里可以正确地复制master数据的slave。

发布/订阅

客户端能够向一个sentinel发送订阅某个频道的事件的命令,当有特定的事件发生时,sentinel会通知全部订阅的客户端。须要注意的是客户端只能订阅,不能发布。

订阅频道的名字与事件的名字一致。例如,频道名为sdown 将会发布全部与SDOWN相关的消息给订阅者。

若是想要订阅全部消息,只需简单地使用PSUBSCRIBE *

如下是全部你能够收到的消息的消息格式,若是你订阅了全部消息的话。第一个单词是频道的名字,其它是数据的格式。

注意:如下的instance details的格式是:

<instance-type> <name> <ip> <port> @ <master-name> <master-ip> <master-port>

若是这个redis实例是一个master,那么@以后的消息就不会显示。

    +reset-master <instance details> -- 当master被重置时.
    +slave <instance details> -- 当检测到一个slave并添加进slave列表时.
    +failover-state-reconf-slaves <instance details> -- Failover状态变为reconf-slaves状态时
    +failover-detected <instance details> -- 当failover发生时
    +slave-reconf-sent <instance details> -- sentinel发送SLAVEOF命令把它从新配置时
    +slave-reconf-inprog <instance details> -- slave被从新配置为另一个master的slave,但数据复制还未发生时。
    +slave-reconf-done <instance details> -- slave被从新配置为另一个master的slave而且数据复制已经与master同步时。
    -dup-sentinel <instance details> -- 删除指定master上的冗余sentinel时 (当一个sentinel从新启动时,可能会发生这个事件).
    +sentinel <instance details> -- 当master增长了一个sentinel时。
    +sdown <instance details> -- 进入SDOWN状态时;
    -sdown <instance details> -- 离开SDOWN状态时。
    +odown <instance details> -- 进入ODOWN状态时。
    -odown <instance details> -- 离开ODOWN状态时。
    +new-epoch <instance details> -- 当前配置版本被更新时。
    +try-failover <instance details> -- 达到failover条件,正等待其余sentinel的选举。
    +elected-leader <instance details> -- 被选举为去执行failover的时候。
    +failover-state-select-slave <instance details> -- 开始要选择一个slave当选新master时。
    no-good-slave <instance details> -- 没有合适的slave来担当新master
    selected-slave <instance details> -- 找到了一个适合的slave来担当新master
    failover-state-send-slaveof-noone <instance details> -- 当把选择为新master的slave的身份进行切换的时候。
    failover-end-for-timeout <instance details> -- failover因为超时而失败时。
    failover-end <instance details> -- failover成功完成时。
    switch-master <master name> <oldip> <oldport> <newip> <newport> -- 当master的地址发生变化时。一般这是客户端最感兴趣的消息了。
    +tilt -- 进入Tilt模式。
    -tilt -- 退出Tilt模式。

TILT 模式

redis sentinel很是依赖系统时间,例如它会使用系统时间来判断一个PING回复用了多久的时间。
然而,假如系统时间被修改了,或者是系统十分繁忙,或者是进程堵塞了,sentinel可能会出现运行不正常的状况。
当系统的稳定性降低时,TILT模式是sentinel能够进入的一种的保护模式。当进入TILT模式时,sentinel会继续监控工做,可是它不会有任何其余动做,它也不会去回应is-master-down-by-addr这样的命令了,由于它在TILT模式下,检测失效节点的能力已经变得让人不可信任了。
若是系统恢复正常,持续30秒钟,sentinel就会退出TITL模式。

BUSY状态

注意:该功能还未实现。

当一个脚本的运行时间超过配置的运行时间时,sentinel会返回一个-BUSY 错误信号。若是这件事发生在触发一个failover以前,sentinel将会发送一个SCRIPT KILL命令,若是script是只读的话,就能成功执行。

Sentinel部署示例

既然你知道了sentinel的基本信息,你能够很想知道应该将Sentinel放置在哪里,须要多少Sentinel进程等等。这个章节展现了几个部署示例。

咱们为了图像化展现配置示例使用字符艺术,这是不一样符号的意思:

+--------------------+ | This is a computer | | or VM that fails | | independently. We | | call it a "box" | +--------------------+

咱们写在盒子里表示他们正在运行什么:

+-------------------+ | Redis master M1 | | Redis Sentinel S1 | +-------------------+

不一样的盒子之间经过线条链接,表示他们能够相互通讯:

+-------------+ +-------------+ | Sentinel S1 |---------------| Sentinel S2 | +-------------+ +-------------+

使用斜杠展现网络断开:

+-------------+ +-------------+ | Sentinel S1 |------ // ------| Sentinel S2 | +-------------+ +-------------+

还要注意:

  • Master 被叫作 M1,M2,M3 ... Mn。

  • Slave 被叫作 R1,R2,R3 ... Rn(replica的首字母)

  • Sentinels 被叫作 S1,S2,S3 ... Sn

  • Clients 被叫作 C1,C2,C3 ... Cn

  • 当一个实例由于Sentinel的行为改变了角色,咱们把它放在方括号里,因此[M1]表示由于Sentinel的介入,M1如今是一个master。

注意永远不会显示的设置只是使用了两个哨兵,由于为了启动故障转移,Sentinel老是须要和其余大多数的Sentinel通讯。

实例1,只有两个Sentinel,不要这样作

+----+ +----+ | M1 |---------| R1 | | S1 | | S2 | +----+ +----+ Configuration: quorum = 1
  • 在这个设置中,若是master M1故障,R1将被晋升由于两个Sentinel能够达成协议而且还能够受权一个故障转移由于多数就是两个。因此他表面上看起来是能够工做的,然而检查下一个点了解为何这个设置是不行的。

  • 若是运行M1的盒子中止工做了,S1也中止工做。运行在其余盒子上的S2将不能受权故障转移,因此系统将变成不可用。

注意为了排列不一样的故障转移须要少数服从多数,而且稍后向全部的Sentinel传播最新的配置。还要注意上面配置的故障转移的能力,没有任何协定,很是危险:

+----+ +------+ | M1 |----//-----| [M1] | | S1 | | S2 | +----+ +------+

在上面的配置中咱们使用完美的对称方式建立了两个master(假定S2能够在未受权的状况下进行故障转移)。客户端可能会不肯定往哪边写,而且没有途径知道何时分区配置是正确的,为了预防一个永久的断裂状态。

全部请永远部署至少三个Sentinel在三个不一样的盒子里。

例2:使用三个盒子的基本设置

这是个很是简单的设置,它有简单调整安全的优点。它基于三个盒子,每一个盒子同时运行一个Redis实例和一个Sentinel实例。

       +----+ | M1 | | S1 | +----+ | +----+ | +----+ | R2 |----+----| R3 | | S2 | | S3 | +----+ +----+ Configuration: quorum = 2

若是M1故障,S2和S3将会商定故障并受权故障转移,使客户端能够继续。

在每一个Sentinel设置里,Redis是异步主从复制,总会有丢失数据的风险,由于有可能当它成为master的时候,一个确认的写入操做尚未同步到slave。而后在上面的设置中有一个更高的风险因为客户端分区一直是老的master,就像下面的图像所示: 

         +----+ | M1 | | S1 | [- C1 (writes will be lost) +----+ | / / +------+ | +----+ | [M2] |----+----| R3 | | S2 | | S3 | +------+ +----+

在这个案例中网络分区隔离老的master M1,因此slave R2晋升为master。然而客户端,好比C1,还在原来的老的master的分区,可能继续往老master写数据。这个数据将会永久丢失,由于分区恢复时,master将会从新配置为新master的slave,丢弃它的数据集。

这个问题可使用下面的Redis主从复制特性减轻,它可在master检查到它再也不能传输它的写入操做到指定数量的slave的时候中止接收写入操做。

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

使用上面的配置(请查看自带的redis.conf示例了解更多信息)一个Redis实例,看成为一个master,若是它不能写入至少1个slave将中止接收写入操做。(N个Slave以上不通就中止接收)

因为主从复制是异步的不能真实的写入,意味着slave断开链接,或者再也不向咱们发送异步确认的指定的max-lag秒数。(断定链接不通的超时时间)

在上面的示例中使用这个配置,老master M1将会在10秒钟后变为不可用。当分区恢复时,Sentinel配置将指向新的一个,客户端C1将可以获取到有效的配置而且将使用新master继续工做。

然而天下没有免费的午饭,这种改进,若是两个slave挂掉,master将会中止接收写入操做。这是个权衡。

例三:Sentinel在客户端盒子里

有时咱们只有两个Redis盒子可用,一个master和一个slave。在例二中的配置在那样的状况下是不可行的,所谓咱们能够借助下面的,Sentinel放置在客户端: 

            +----+ +----+ | M1 |----+----| R1 | | S1 | | | S2 | +----+ | +----+ | +------------+------------+ | | | | | | +----+ +----+ +----+ | C1 | | C2 | | C3 | | S1 | | S2 | | S3 | +----+ +----+ +----+ Configuration: quorum = 2

在这个设置里,Sentinel的视角和客户端的视角相同:若是大多数的客户端认为master是能够到达的,它就是好的。C1,C2,C3是通常的客户端,这不意味着C1识别单独的客户端链接到Redis。它更像一些如应用服务,Rails应用之类的。

若是运行M1和S1的盒子故障,故障转移将会发生,然而很容看到不一样的网络分区将致使不一样的行为。例如若是客户端和Redis服务之间的断开链接,Sentinel将不能设置,由于master和slave将都不可用。

注意若是使用M1获取分区,咱们有一个和例二中描述的类似的问题,不一样的是这里咱们没有办法打破对称,因为只有一个slave和master,因此当它的master断开链接时master不能中止接收查询,不然在slave故障期间master将永不可用。

因此这是个有效的设置可是在例二中的设置有像更容易管理HA系统的优势, 并有能力限制master接收写入的时间。

例4:少于3个客户端的Sentinel客户端

在例3中若是客户端少于3个就不能使用。在这个案例中咱们使用一个混合的设置:

            +----+ +----+ | M1 |----+----| R1 | | S1 | | | S2 | +----+ | +----+ | +------+-----+ | | | | +----+ +----+ | C1 | | C2 | | S3 | | S4 | +----+ +----+ Configuration: quorum = 3

这里和例3很是相似,可是这里咱们在4个盒子里运行四个哨兵。若是M1故障其余的三个哨兵能够执行故障转移。

本文参考文档:

https://redis.io/topics/sentinel

http://redis.majunwei.com/topics/sentinel.html

http://www.javashuo.com/article/p-vguqgocn-gw.html

http://www.javashuo.com/article/p-obsenvtg-go.html

总结

接下来是你们最喜欢的总结内容啦,内容有二,以下:

一、但愿能关注我其余的文章。

二、博客里面有没有很清楚的说明白,或者你有更好的方式,那么欢迎加入左上方的2个交流群,咱们一块儿学习探讨。

相关文章
相关标签/搜索