下面内容翻译自网页:http://redis.io/topics/sentinel
Redis Sentinel提供了Redis的高可用性方案。在实际中着意味着你可以通过使用Sentinel来创键一个Redis的方案来在不需要在认为干预的条件下防止某种类型的错误发生。
Redis Sentinel也提供了一些附属的任务,比如监控,通知和作为客户端的一个配置提供者。
下面是从宏观角度看的Sentinel能力的一个完整列表
Redis Sentinel 是一个分布式系统:
Sentinel本身被设计在有多个Sentinel进程协同工作的环境中运行的。有多个Sentinel进程协同的优点如下:
总结一下:Redis实例(主服务器和从服务器)和客户端连接到Sentinel和Redis,这同样是一个有特定属性的分布式系统。本文档会逐步介绍这些概念,从一些了解Sentinel属性所需的基本知识开始,到为了更准确的理解Sentinel是如何工作的一些复杂的信息(这些是可选的)。
Sentinel的当前版本是Sentinel 2.这是对最初的Sentinel实现使用了更强大和简明的预测算法(文档中会进行说明)进行重写后的版本。
稳定的Redis Sentinel版本是随同Redis2.8和3.0发布的,这是两个Redis的最新版本。
新的发布会在非稳定分支中,而新的特性当认为是稳定的时候有时会往前归入到2.8和3.0的版本中。
edis Sentinel版本1,伴随的Redis2.6已经被丢弃,不应该再被使用。
如果你使用的是redis-sentinel的可执行文件(或者你有一个符号连接到一个redis-server的可执行文件上)你可以通过下面的命令来执行Sentinel:
redis-sentinel /path/to/sentinel.conf
另外你可以直接使用redis-server的可执行文件,以Sentinel的模式启动:
redis-server /path/to/sentinel.conf --sentinel
两种方式都是一样的。
不管怎么样,运行Sentinel都必须使用一个配置文件,这个配置文件会被系统使用来保存当前的状态以便重启的时候进行装载。Sentinel会在没有配置文件或配置文件不可写的时候拒绝启动。
Sentinels默认运行时监听TCP端口26379为了Sentinels可以工作,你的服务器的26739端口必须打开,并接受其它Sentinel实例的IP地址的连接,否则Sentinels之间无法对话,也无法统一该做什么,因此故障转移永远不会发生。
Redis源码发布中包含一个称为sentinel1.con的配置文件,这是一个自我说明的示例配置文件,你可以用它来配置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
你只需指定要监控的主服务器,每一个单独的主服务器需要一个单独的名字(可能有多个从服务器)。不需要配置从服务器,从服务器是自动发现的。Sentinel1会自动更新配置文件,添加关于从服务器的信息(为了在重启的情况下维持这些信息)。配置同样会在每次某个从服务器在故障转移时被推举为主服务器和每一次一个新的Sentinel被发现时被更新。
上面配置的例子,配置了监控Redis实例的两个集合,每一个包含一个主服务器和一个未确定数量的从服务器,一个实例集合称为mymaster,另一个为resque.
Sentinel moniter声明参数的含义如下:
sentinel monitor
为了更加清楚,我们逐行来解释这些选项的含义:
第一行用来告诉Redis去监控一个主服务器称为mymaster,地址是127.0.0.1,端口是6379,法定人数为2,每一个参数都很清楚了,除了这个quorum参数:
举个例子,加入有5个Sentinel进程,而对一个主服务器集合给定的quorum是2,则会如下:
在实际的情况中这意味着在故障期间如果大多数的Sentinel进程无法相互通信,Sentinel是不会启动一个故障转移的(故障转移不会发生在小部分区间)。
其他的选项格式如下:
sentinel
目的如下:
down-after-milliseconds
设置了当超过指定的毫秒时间后一个实例没有响应PINGS或返回错误的情况下Sentinel会认为这是不可用的。
parallel-syncs
设置了在故障转移之后会同时被重新配置到新的主服务器上的从服务器的数量,数字越低,故障转移完成花费的时间就越长,然而如果从服务器被配置来使用了就的数据,你可能不想所有的从服务器都同时和主服务器进行重同步。虽然复制进程一般来说是不会阻塞从服务器的,但又一个时间段会停下来装载从主服务器中获取的快数据,你可能想确保只有一个从服务器是一个时间段是不可用的,可以通过设置该选项为1.
其它的选项在本文档的其它地方和随Redis发布的示例配置文件sentinel.conf1中会进行描述。
所有的配置参数在运行是都是可以改变的,并且通过SENTINEL SET 命令可以促使其生效。可以参看—运行时重新配置Sentinel – 章节来获取更多信息。
在你已经知道了关于Sentinel的基本信息,你可以想知道该在什么地方部署Sentinel进程,需要部署多少个Sentinel进程等等,本章节会显示一些部署示例
我们使用ASCII 艺术来以图形的格式来展示例子,这里有一些不同含义的符号:
+--------------------+
| 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 |
+-------------+ +-------------+
还有一些注意的地方:
注意,不会展示只有两台Sentinels被使用时的场景,因为Sentinels总是需要在多数Sentinel间对话来启动故障转移。
+----+ +----+
| M1 |---------| R1 |
| S1 | | S2 |
+----+ +----+
配置: quorum = 1
注意到大多数是需要用来安排不同的故障转移后后续的最新配置文件传递到所有的Ssentinel的,也要注意到在这个配置如果中一个节点中可以进行故障转移,而不需要任何达成的一致,会是非常危险的。
+----+ +------+
| M1 |----//-----| [M1] |
| S1 | | S2 |
+----+ +------+
在上面的配置中我们产生了两个主服务器(假定S2可以未经授权进行故障转移),以完全对称的方式。客户端可能向两边都写入了无限的数据,而当隔离恢复的时候就无法确定那边的配置是正确的了,这就是要防止产生的永久隔离大脑情况。
所以请在不同的箱子中部署至少3个Sentinel.
着是一个非常简单的配置,这有可以简单的调整来增加安全性的优点,基于3个箱子,每一个箱子运行一个Redis进程和一个Sentinel进程。
+----+
| M1 |
| S1 |
+----+
|
+----+ | +----+
| R2 |----+----| R3 |
| S2 | | S3 |
+----+ +----+
配置: quorum = 2
如果主服务器M1失败,S2和S2会认同失败,并可以授权失败转移,使得客户端可以继续连接。
在每一个Sentinel设置中,因为Redis是异步复制的,因此总是存在损失一些写操作的危险,因为认可的写可能还没有达到会被推举为主服务器的从服务器。然而在上面的配置对于客户端来说有一个更改的风险是由于旧的主服务器被隔离开了,向下面图片显示的一样。
+----+
| M1 |
| S1 | <- C1 (writes will be lost)
+----+
|
/
/
+------+ | +----+
| [M2] |----+----| R3 |
| S2 | | S3 |
+------+ +----+
在这个例子中,一个网络中断隔离了旧的主服务器M1,因此R2被推举为主服务器,然而客户端,比如C1,和就的主服务器在同一个网络区间,可能会继续往旧的主服务器写数据,这些数据在隔离恢复的时候会永久的丢失,因为旧的主服务器会被重新配置为新主服务器的从服务器,而忽略自己的数据集合。
这个问题可以通过使用以下的Redis复制特点来缓和,这允许当主服务器监测到无法传输写到指定数量的从服务器时拒绝写操作。
min-slaves-to-write 1
min-slaves-max-lag 10
当使用上面的配置时(请查看在Redis发布中的自注释的redis.conf例子获取更多信息)一个Redis实例,当作为一个主服务器时会在其无法向至少一个从服务器写时停止接受写操作。因为复制是异步的,无法写就意味着从服务器要么是无法连接,要么是无法在最大的max-lag数量的秒数内返回异步的相应。
使用这个配置,上面例子中旧的Redis主服务器M1会在 10秒变为不可用。当隔离恢复时,Sentinel配置会变成一个心底,客户端C1可以获取一个合法的配置,并继续连接到新的主服务器。
没有免费的午餐,在这个精确的控制下,如果两个从服务器都宕机,那主服务器将拒绝接收写,这就是交换。
有时候我们只有两个Redis箱子可用,一个用来作为主,一个作为从,那例子2种的配置就无法使用了,我们可以采用下面的手段,Sentinel被安置到客户端。
+----+ +----+
| M1 |----+----| R1 |
| S1 | | | S2 |
+----+ | +----+
|
+------------+------------+
| | |
| | |
+----+ +----+ +----+
| C1 | | C2 | | C3 |
| S1 | | S2 | | S3 |
+----+ +----+ +----+
配置: quorum = 2
在这个配置中,Sentinels的视角和客户端是一样的:如果一个主服务器是大多数的客户端可以连接的,那就是好的。C1,C2,C3是普通的客户端,这不意味着C1只是一个连接到Redis的单一客户端,它通常是类似应用服务器,Redis应用或其他的。
如果M1和S1所在的箱子失败了,故障转移会毫无疑问的发生,然而看懂啊不同的网络隔离会造成不同的行为,比如Sentinel会在客户端和Redis服务无法连接的时候无法配置,因为Redis的主服务器和从服务器都已经不可用了。
注意到如果C3和M1被隔离了(对于上面的网络情况来说是几乎是不可能的,但是更可能会由于不同的层次造成的,或则由于软件层的失败),就和例子2种的情况有些类似了,不同的是我们没有办法破坏对称,因为只有一个主服务器和从服务器,因此只有要么主服务器继续接收请求或者是由于从服务器的故障而永远不可用。
因此这是一个可用的配置,但是例子2更有优点,因为Redis的高可用系统和Redis本省运行在同样的箱子中,这样便于管理,也可以限制当主服务器称为少数隔离是可以接收写的时间间隔。
例子三描述的情况在当没有3个客户端的情况下无法使用(比如3个web服务器),在这个情况下我们需要采用像下面的混合配置:
+----+ +----+
| M1 |----+----| R1 |
| S1 | | | S2 |
+----+ | +----+
|
+------+-----+
| |
| |
+----+ +----+
| C1 | | C2 |
| S3 | | S4 |
+----+ +----+
配置: quorum = 3
这很像例子3,但是我们在可用的4个箱子中运行了4个Sentinel,如果M1不可用,其它的3个Sentinels会执行故障转移。
理论上这个配置在C2和S4所在的箱子移除时,将quorum设置成2也可以工作。然而这时不可行的,因为我们期望Redis的高可用性保持在Redis端,而不是依赖于应用层。
Docker使用端口映射的技术:运行在Docker容器内的程序可能会暴露为一个和程序认为在使用的端口不通的端口。这样在多个容器同时使用同一服务器的同一端口的情况下是有用的。
Docker不是这种功能的唯一如软件,有一些其它的网络地址转换工具不仅可以映射端口,连IP地址都可以映射。
映射端口和地址会对Sentinel以下面两种形式产生问题:
因为Sentinels使用Maseters的INFO 输出信息来监测从服务器,监测到的从服务器将是无法到达的,Sentinel也就永远无法进行故障转移了,这是因为从系统的角度当前没有一个正常的从服务器,也就没有方法在部署Docker的情况下去使用Sentinel来监控这个主服务器和从服务器实例的集合了,出发你制定Docker端口是1:1映射的。
因为存在上面的问题,在你想要使用Docker来指向端口(或者其他的进行端口映射的工具)的情况下来使用Sentinel实例,你可以使用下面的Sentinel配置指令来迫使Sentinel来声明一个IP和端口集:
sentinel announce-ip
sentinel announce-port
注意到Docker有能力运行在host networking mode下(检查–net=host配置项)。在这个配下不会造成任何问题,因为端口不会被重映射。
在文档的下个章节,所有关于Sentinel API,配置和语义的细节都会被逐渐的覆盖到,对于尽快想要使用系统的人,本章是一个显示如何快速配置和使用3个Sentinel实例的指导。
这里假定实例使用端口5000,5001,5002。我们同样假定在6379上运行Redis master,而salve运行在6380上。使用IPV4回送地址127.0.0.1,假定你在你的个人电脑上运行模拟器。
3个Sentinel配置文件应该看起来是这样子的:
port 5000
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1
其它的两个配置文件中使用5001,5002来作为端口。
关于上面的配置有一些需要说明:
你启动了3个Sentinel, 你会看到日记中的一些信息,比如:
+monitor master mymaster 127.0.0.1 6379 quorum 2
这是一个Sentinel时间,后面你如果设置了订阅的事件名称,你可以通过Pub/Subb接收到事件。
Sentinel会在失败检测和故障转移过程中生成和记录不同的事件。
Sentinel开始使用最常见的一件事情是检查监控的主服务器的状态:
$ redis-cli -p 5000
127.0.0.1:5000> sentinel master mymaster
1) "name"
2) "mymaster"
3) "ip"
4) "127.0.0.1"
5) "port"
6) "6379"
7) "runid"
8) "953ae6a589449c13ddefaee3538d356d287f509b"
9) "flags"
10) "master"
11) "link-pending-commands"
12) "0"
13) "link-refcount"
14) "1"
15) "last-ping-sent"
16) "0"
17) "last-ok-ping-reply"
18) "735"
19) "last-ping-reply"
20) "735"
21) "down-after-milliseconds"
22) "5000"
23) "info-refresh"
24) "126"
25) "role-reported"
26) "master"
27) "role-reported-time"
28) "532439"
29) "config-epoch"
30) "1"
31) "num-slaves"
32) "1"
33) "num-other-sentinels"
34) "2"
35) "quorum"
36) "2"
37) "failover-timeout"
38) "60000"
39) "parallel-syncs"
40) "1"
可以看到,这里打印了关于主服务器的一些信息。有一些是我们感兴趣的:
为了显示实例的更多信息,你可以使用下面的两个命令:
SENTINEL slaves mymaster
SENTINEL sentinels mymaster
第一个命令会提供连接到主服务器的从服务器的类似信息,第二个是关于其它Sentinel的。
前面提到过,Sentinel也可以作为一个想连接到主服务器和从服务器集的客户端的配置提供者。因为可能发生故障转移或重新配置,客户端并不知道当前活跃的实例集中主服务器,所有Sentinel提供一个API来实现这个功能:
127.0.0.1:5000> SENTINEL get-master-addr-by-name mymaster
1) "127.0.0.1"
2) "6379"
到目前为止,我们的Sentinel部署已经可以进行测试了,我们杀死主服务器,然后检查下配置是否改变,只需要:
redis-cli -p 6379 DEBUG sleep 30
这个命令会使得我们的主服务无法连接,休眠30秒,这基本上可以模拟了由于某些原因造成的主服务器失败状态。
果你检查Sentinel日记,你会发现一些事情:
如果你在重新查询mymaster当前主服务器的地址,最终我们会获得一个和之前不同的响应:
127.0.0.1:5000> SENTINEL get-master-addr-by-name mymaster
1) "127.0.0.1"
2) "6380"
到目前一切都正常,你可以能想去创建自己的Sentinel部署,或者了解关于Sentinel 命令和内部的更多内容了。
Sentinel提供了检查自身状态,检查监控的主服务器和从服务器的状态,订阅来接收特定通知和运行时改变Sentinel配置的API。
默认情况下,Sentinel使用TCP端口26379(6379一般是Redis端口),Sentinels使用Redis协议来接收命令,所以可以使用redis-cli或其他未修改的Redis客户端来和Sentinel进行回话。
直接向Sentinel查询从其角度看来监控的Redis服务器状态是可能的,来查看其所知道的其它的Sentinel等。另外可以使用Pub/Sub,来从Sentinels接收Push类型的通知,没当时间发生,比如故障转移或某个实例进入了错误的状态等。
The following is a list of accepted commands, not coveringcommands used in order to modify the Sentinel configuration, which are coveredlater.
下面是Sentinel接受的命令列表,并不包括用来修改Sentinel配置的命令,其它的会在后面涉及到。
显示指定的主服务器的状态
显示指定的主服务器的从服务器列表和状态
显示指定的主服务器对应的Sentinel列表和状态
返回指定名字的主服务器的IP和端口,如果正在发生故障转移或该主服务器正常关闭了,则返回推选的从服务器的地址和IP。
本命令重置所有复合模式的主服务器,模式参数是一个glob-style模式,重置进程清楚主服务器的任何前期状态(包括正在发生的故障转移),移除所有发现的相关的从服务器和Sentinel
当主服务器无法连接时,没有询问其他Sentinels而强制执行一个故障转移,(这样后,一个新版本的配置文件会被发布,其它的Sentinel会更新配置文件)
检查当前的Sentinel配置是否可以达到需要进行故障转移的和转移授权的法定数量,本命令应该用来监控系统,检查Sentinel部署是否正常。Redis2.8.4版本开始,Sentinel提供了一个API来对一个指定主服务器的配置进行增加,删除和修改。注意到如果你有多个Sentinel,你应该将这些改变作用到你所有的Redis Sentinel实例。这意味着修改单个Sentinel的配置不会自动将改变传递到网络上的其它Sentinel上。
下面是Sentinl的一些修改Sentinel实例配置的命令列表
该命令告诉Sentinel开始监控一个新的主服务器,有指定的名字,IP,端口和法定数量。它和Sentinel配置文件中的monitor指令是一样的,区别是这里不能使用主机名来作为IP,需要提供一个ipv4或ipv6的地址。
用来移除指定的主服务器,该主服务器不会再被监控,会完全从Sentinel的内部状态中移除,因此也不会再出现在Sentinel的主服务器列表中。
SET命令和Redis的CONFIG SET命令很像,用来改变指定主服务器的配置参数,可以指定多个option/value对。所有可以在Sentinel.conf中配置的参数都可以使用SET命令进行设置。下面是一个使用SET命令来改变名为object-cache-master的主服务器的down-after-milliseconds配置的例子:
SENTINEL SET objects-cache-master down-after-milliseconds 1000
前面提到,SENTINEL SET可以用来设置启动配置文件中可用的所有参数,另外也可以用来指示改变主服务器的法定数量配置,而不用移除或重新添加主服务器(使用SENTINEL MONITOR 和SENTINEL REMOVE),值需要简单使用:
SENTINEL SET objects-cache-master quorum 5
注意没有更SET对应的GET命令,因为SENTINEL MASTER以一种易于解析的格式提供了所有的配置参数(像一个 field/value对数组)
对你的部署添加一个新的进程是非常简单,因为Sentinel实现了自动发现的机制。你需要做的所有事情就是启动一个Sentinel并配置成监控当前活跃的主服务器,在10秒钟之内Sentinel会获取到其它Sentinel的列表和对应主服务器的从服务器集合。
如果你需要通知增加多个Sentinel,建议是一个个的添加,等到其它Sentinel都已经发现第一个后再增加下一个。这是为了保证大多数是会划分到一个区间里面的,这样再增加的过程中故障转移也能正常进行。
这可以简单的通过再网络畅通的情况下每隔 30秒的延迟添加一个新的Sentinel来实现。
最后可以通过使用SENTINEL MASTER mastername 命令来检查是否所欲的Sentinel都对监控的主服务器的Sentinel数量保持一致。
移除一个Sentinel就有一点复杂了:Sentinel永远不会忘记一个已经存在的Sentinel。即使是已经是很长世间都无法连接的。这是因为我们不想动态的改变需要用来授权一个故障转移和新配置创建的数量。为了移除一个Sentinel,需要在网络畅通的情况下进行下面的步骤:
Sentinel不会忘记给定的主服务器的从服务器,即使是已经长时间无法连接了。这在发生网络隔断或故障转移是能够正确的重新配置一个重新可用的从服务器时是有用的。
另外,在故障转移之后,发生故障的主服务器会虚拟的添加有新主服务器的一个从服务器,也会再可用的时候从新配置成新主服务器的一个复制。
然而有时候需要Sentinel的从服务器列表中永久的移除一个从服务器(这也可能是旧的主服务器)
为了实现这个目的,你需要像所有的Sentinel发送SENTINELRESET masetername命令,他们会再10秒内更新从服务器的列表,仅仅增加当前主服务器INFO输出中存在的从服务器。
客户端可以使用Sentinel来左右一个和Reids兼容的发布/订阅服务器(但是不能使用PUBLISH)来SUBSCRIBE或PSUBSCRIBE到通道上来获取特定的事件。
通道名和时间名是一样的。比如名字未+sdown的通道会在关联的实例进行一个SDOWN情况是接收到通知(SDOWN意味着该实例从你查询的Sentinel的角度来看是不可连接的)
可以通过使用PSUBSCRIBE * 来获取所有的信息。
下面是使用该API可以获取的通道列表和消息格式。第一个词是通道或事件的名称,剩下的是数据的格式。
注意:instance details是指使用以下参数来确定的一个目标实例。
@
定义主服务器的部分(从@参数开始到结束)是可选的,只有在指定的实例不是主服务器时才需要。
--主服务器重启.
-- 一个新的从服务器被发现并绑定.
-- Failover 状态改变为 reconf-slaves
状态.
-- 由另一个Sentinel启动了故障转移或其它外部的实体被监测到(一个绑定的从服务器转变为主服务器)。
--首领SENTINEL发送了SLAVEOF 命令到该实例来重新配置新的从服务器。
-- 从服务器被配置为一个新的主服务器(ip:port)的从服务器,但是同步的进程还没有完成
-- 从服务器和新的主服务器完成了同步
--一个或多个Sentinel针对主服务器被认为是重复的而被移除(这发生在Sentinel实例进行重启时)
--检测到主服务器的一个新的Sentinel和绑定。
-- 指定实例处于Subjectively Down状态。
--指定实例不在处于Subjectively Down状态。
--指定实例处于Objectively Down状态.
--指定实例不再处于Objectively Down状态。
--当前epoch被更新了.
--新的故障转移在进行中,等待被多数选定。
-- 赢得特定epoch的选举,可以进行故障转移
--新的故障转移状态:select-slave:正在尝试找到一个合适的从服务器来提升。
--没有合适的从服务器来进行提示,会在一段时间后重试,但是可能会发生变化,状态机可能会完全放弃这次的故障转移。
-- 找到了一个适合提升的从服务器。
--正在尝试重新配置被提升的从服务器为主服务器,等待其进行转换。
--故障转移由于超时而中断,从服务器最终会被配置为其它的新的主服务器的复制。
--故障转移成功完成,所有的从服务器会被重新配置为新的主服务器的的复制。
-- 主服务器在配置改变会会更新新的IP和端口,这个信息通常是外部用户会感兴趣当Lua脚本运行的时间超过了配置的Lua脚本运行时间限制Redis会返回-BUSY状态。当这种情况发生在触发故障转移之前,Sentiel会重试发送SCRIPT KILL命令,只有在脚本是只读的情况下该命令才会成功。
如果实例再执行了这个尝试之后仍然处于错误状态,它最终会被故障转移掉。
Redis实例有一个称为slave-priority的配置参数,该信息会被Redis 从服务器在其INFO输出中显示。Sentinel使用改内容来在进行故障转移时挑选从服务器:
比如有一个从服务器S1和当前的主服务器处于同一个数据中心,另一个从服务器S2在另外一个数据中心,就可能设置S1的优先级为10,S2优先级为100,这样当主服务器发生故障时,如果S1和S2都是可用的,那S1会被优先选择。
关于从服务器被选择的方法的更多信息,可以查看从服务器选择和优先级章节。
当主服务器配置为需要客户端提供密码时,也就是一种安全的方法,从服务器在创建用于复制的主-从连接时需要提供这个密码以便主服务器可以认定
可以通过下面的配置指令来实现:
当Sentinel使用时,没有一个单一的主服务器,因为在故障转移之后从服务器可能扮演主服务器的角色,而旧的主服务器可以被重新配置为从服务器。因此需要做的就是在所有实例中都配置上面的两条指令,包括主服务器和从服务器。
这也是一种合理的设置,因为你不仅是只想保护在主服务器中的数据,在从服务器中也保持同样的数据获取限制。
然而在一些不常用的情况下,你想要提供一个从服务器来进行未授权的访问,你可以通过设置该从服务器的优先级为0来实现,这样就保证该从服务器不会被推选为主服务器,只需要在这个从服务器中配置masterauth指令,不需要配置requirepass指令,这样就可以使用未授权的客户端来获取数据了。
Sentinel requires explicit client support, unless thesystem is configured to execute a script that performs a transparentredirection of all the requests to the new master instance (virtual IP or othersimilar systems). The topic of client libraries implementation is covered inthe document Sentinel clientsguidelines.
Sentinel需要客户端直接的支持,除非系统配置了一个脚本来透明的将所有请求重新发送到新的主服务器实例(虚拟IP或其它类似的系统)。关于客户端库实现的主题在Sentinel 客户端指导中会涉及。
下面章节中我们会覆盖Sentinel如何工作的部分内容,具体的实现细节和算法会在本文档的最后部分涉及。
Redis Sentinel有两个宕机的不同概念,一个是SubjectivelyDown ,这是某一个给定的Sentinel实例判断的状态,另一个为Objectively Down,这是当足够多的Sentinel(至少是监控的主服务器配置的法定数量)都出现了SDOWN条件,并且通过SENTINELis-master-down-by-addr命令得到了其它Sentinel的反馈。
从Sentinel的角度来看,SDOWN情况是当没有在配置中由is-master-down-after-milliseconds配置的秒数内从主服务器收到PING请求的合法响应。
PING的合法响应包括:
任何其它的响应(或者没有响应)都认为是不合法的。注意,如果以逻辑上的主服务器在其INFO中宣称自己是从服务器,则认为其宕机了。
注意 SDOWN是指在配置的指定秒数内没有合法响应,所以比如内部配置了30000毫秒(30秒),而我们在29秒时收到PING的响应,认为该实例是正常工作的。
SDOWN状态不足以出发一个故障转移:它只意味这一个单个的Sentinel认为Redis实例已经不可用了,要触发故障转移,必须达到ODOWN状态。
从SDOWN转换到ODOWN,并没有使用到强一致的算法,只是一种散播的方式:如果一个给定的Sentinel在给定的时间范围内收到足够多的Sentinel报告说主服务器已经宕机了,则SDOWN改变为ODOWN。如果响应丢失了,则清楚该标志。
更加严格的授权会使用要求的大多数来真正启动故障转移,但是没有故障转移可以在未到达ODWON状态之前触发。
ODWON状态只作用于主服务器,对于其他类型的实例,Sentinel不要求去执行,从服务器和其它的SENTINELS永远不会达到ODOWN状态,只会出现SDOWN状态。
然而SDOWN也有语义暗示,比如一个从服务器属于SDOWN状态则在故障转移时不会被推选为主服务器。
Sentinel会保持和其它Sentinel的连接,这样就可以相互的检查各自的可用性和交换信息。然而你不需要在每一个Sentinel实例中配置一个其它Sentinel的地址,因为Sentinel使用Redis实例的发布/订阅能力来自动发现监控同一个主服务器的其它的Sentinel和从服务器。
这个功能是通过向名字为__sentinel__:hello的通道发送hello信息来实现的。
类似的,你不需要配置主服务器相关的从服务器的列表,因为Sentinel会自动发现这个Redis列表。
__sentinel__:hello
每两秒发送一个信息,来声明它的存在,包括IP,PORT,runid.
__sentinel__:hello
通道来发现未知的sentinel.当新的sentinel被监测到,他们会被添加到这个主服务器的Sentinel列表来。
Specifically:即使是没有发生故障转移,Sentinel也会尝试去配置监控实例的当前配置,特别是:
为了Sentinel可以重新配置从服务器,错误的配置必须在某些时刻被发现,这会大于用来广播新配置的时间。
这样会阻止一个有失效配置的Sentinel会去在接收到更新之前去改变从服务器的配置。
另外要注意到总是尝试使用最新的配置是如何保证故障转移对于分区来说更加可靠:
关于本章要记住的重要一点是:Sentinel是一个每个进程都会尝试应用最新的配置到监控的实例的系统。
当Sentinel实例准备执行一个故障转移时,(主服务器处于ODOWN状态,Sentinel收到大多数Sentinel实例的授权来进行故障转移),一个合适的从服务器会被选中。
从服务器选择进程评估从服务器的下列信息:
一个从服务器发现和主服务器失去连接超过了配置的主服务器(down-after-milliseconds 选项)的十倍,再加上从Sentinel进行故障转移的角度来看主服务器也是不可用了,会被认为是不适合进行故障转移而被跳过。
用更严密的话来说就是一个从服务器的INFO输出中显示已经和主服务器失联超过:
会被认为是不可靠的,而完全不被考虑。
从服务器选举制考虑通过了上面的检查的,并按照上面的标准按照下面的顺序进行排序:
Redis主服务器(可能在故障转移之后会被转换为从服务器),和从服务器都强烈建议配置一个从服务器优先级。否则所有的实例可能都会使用默认的runID(这是建议的设置,因为比起按照复制偏移来选择从服务器来说更加的有趣)
一个Redis实例可以配置特殊的slave-priority:0,这样该实例就永远不会被Senitnel在故障转移时选择为新的主服务器,区别就是这个使用永远不会成为主服务器。
下面章节我们会解释下Sentinel行为的细节,对于用户来说了解所有的细节不是必须的,但是对Sentinel的深入了解可能对更有效的部署和操作Sentinel会有帮助。
之前的章节中提到,由Sentinel监控的主服务器都会配置一个quorum.这指定了需要对主服务器不可用或错误达成一致并出发故障转移的Sentinel的进程数量。
然而,当故障转移出发后,为了让故障转移真正发生,至少要有大部分的Sentinels授权某个Sentinel进行故障转移,隔离在小部分区间的Sentinel永远不会执行故障转移。
让我们描述的更清晰一点:
这个区别可能看起来很微妙,但很好理解。比如如果有5个Sentinel实例,quorum设置为2,当2个Sentinel认为主服务器不可用了就会出发Sentinel,这两个Sentinel中的一个只有在获取到至少3个Sentinel的授权之后才可以进行故障转移。
如果quorum设置为5,则所有的Sentinel都必须认同主服务器处于错误状态,所有的Sentinel都必须授权才可以进行故障转移。
这意味着quorum可以用来以下面两种方式来调整Sentinel
Sentinel要求得到大部分的授权才启动故障转移是由于一下一些重要的原因:
当一个Sentinel被授权以后,会获得进行故障转移的主服务器的一个唯一的配置纪元,这个一个用来在故障转移完成后标识配置新版本的数字。因为大部分都同意了这个版本是指派为某一个Sentinel,而其它的Sentinel就不能使用了,这意味着每一次故障转移的每一个配置都会是一个唯一的版本。我们会看到为什么这很重要。
另外Sentinel有一个规则:如果一个Sentinel选择了其它的Sentinel来对一个主服务器进行故障转移,它会等待一些时间,然后去尝试对同样的主服务器进行故障转移,这个延迟就是sentinel.conf中配置的failover-timeout.这意味着Sentinel不会同时对同一个主服务器进行故障转移,第一个获取授权的会先尝试,如果失败了,另一个会在一定时间后再尝试,照此下去。
Redis Sentinel保证一个活跃属性:当大部分Sentinel可以相互会话时最终其中的一个在主服务器宕机后会被授权来进行故障转移。
Redis Sentinel同样保证一个安全属性:每一个Sentinel会使用不同的配置纪元来对同一个主服务器进行故障转移。
当一个Sentinel能够承购的完成主服务器的故障转移,它会对新的配置进行广播,这样其它的Sentinel会更新他们关于主服务器的信息。
要使得故障转移认为是成功的,需要Sentinel发送SLAVEOFNO ONE 命令到选中的从服务器,然后可以从INFO输出中观察到该从服务器转换为了主服务器。
在这个时刻,即使从服务器的重配置还在进行中,故障转移也认为已经成功了,然后所有的Sentinel需要开始记录新的配置。
新配置传播的方式也是我们需要每一个Sentinel的故障转移由一个不同的版本数字来认证的原因(配置纪元)
每一个Sentinel使用Redis的发布/订阅持续的广播其主服务器的配置版本,不进在主服务器,也在所有的从服务器进行。同时Sentinel也等待信息来查看其它的Sentinel宣称的配置。
配置在__sentinel__:hello 发布/订阅通道上广播。
因为每一个配置有一个不同的版本信息,所有更大的版本总是会替换所有小的版本。
因此比如mymaster配置开始时所有的Sentinel都认为主服务器是192.168.1.50:6379。配置版本为1,一段时间后,一个Sentinel被授权来进行故障转移,版本为2,当故障转移成功后,它会广播一个新的配置,假定是192.168.1.50:9000,版本2。所有的其它实例会看到这个配置,并会相应的更新他们的配置,就是因为新的配置有一个更高的版本。
这标识Sentinel保证了第二个活跃属性:一个Sentinel集合如果可以相互通讯会集中使用同一个更高版本的配置。
基本上如果网络是隔离的,而每一个隔断会聚合到一个高的本地配置,在没有隔断的特定情况下,所有的Sentinel会对配置达成一致。
Redis Sentinel配置最终是一致的,一次每一个隔离会聚集到一个可用的较高的配置。然而在使用Sentinel的真实环境中,有3个不同的角色:
为了定义系统的行为,我们必须考虑到所有。
下面是一个有3个节点的简单网络,每一个节点运行一个Redis实例和一个Sentinel实例:
+-------------+
| Sentinel 1 |----- Client A
| Redis 1 (M) |
+-------------+
|
|
+-------------+ | +------------+
| Sentinel 2 |-----+-- // ----| Sentinel 3 |----- Client B
| Redis 2 (S) | | Redis 3 (M)|
+-------------+ +------------+
在这个系统中,原始状态是Redis3是主服务器,Redis1,2是从服务器。一个隔断发生后隔离了旧的主服务器,Sentinel 1,2会启动一个故障转移,假定推选了Redis1做为新的主服务器。
Sentinel的属性保证了Sentinel1和2现在有关于主服务器的同样配置,然而Sentinel3依然保留着旧的配置,因为它被隔离在不同的区间里。
我们知道Sentinel3会在网络隔断恢复后更新配置,然而如果有客户端和旧的主服务器隔断在同一个区间会发生什么呢?
客户端会依然可以写Redis3(旧的主服务器),当区间重新连接后,Redis会被调整为Redis1的从服务器,所有在隔离期间写入的数据将丢失。
依据你的配置,你可能期望或不期望发生这样的事情:
因为Redis是异步复制的,是没有办法完全保证这个场景中的数据丢失,然而你可以在Redis3和Redis1中限制这种分歧,使用以下配置:
min-slaves-to-write 1
min-slaves-max-lag 10
有了上面的配置(可以查看在Redis发布版本中自解释的redis.conf实例获取更多的信息),一个Redis实例当作为主服务器是,如果不能实际写向至少一个从服务器时会拒绝接收写请求,因为复制是异步的,不能实际写指的是或者是从服务器失去了连接,或则是在超过了指定max-lag的描述后没有收到异步的响应。
使用这个配置后,上面例子中的Redis 3会在10秒后不可用,当隔断恢复后,Sentinel配置会更新到新的版本,客户端B可以获取一个合法的配置然后继续使用。
In general Redis + Sentinel as a whole are a an eventually consistent systemwhere the merge function is last failover wins, and the data from old masters arediscarded to replicate the data of the current master, so there is always awindow for losing acknowledged writes. This is due to Redis asynchronousreplication and the discarding nature of the "virtual" merge functionof the system. Note that this is not a limitation of Sentinel itself, and ifyou orchestrate the failover with a strongly consistent replicated statemachine, the same properties will still apply. There are only two ways to avoidlosing acknowledged writes:
总的来说 Redis+Sentinel 作为一个整体最终是一个始终保持一致的系统,整合的方法就是最后的故障转移会胜出。旧的主服务器的数据会被忽略,然后从新的主服务器复制数据,因此总是有一个窗口会丢失已认可的写,这是由Redis的异步复制来决定的和系统的虚拟融合功能的本质决定的。注意到这不是Sentinel本事的一个限制,如果你使用一个强一致的复制状态机器来进行故障转移,依然会出现同样的特点。只有两种方法可以保证不丢失认可的写:
Redis当前不能使用上述的任何一个系统,当前也是在部署的目标之外的。然而在Redis存储之上有一些替代的实现方案2比如 SoundCoud Roshi或者 Netflix Dynomite.
Sentinel状态会被固话在Sentinel的配置文件中,比如每一次收到关于主服务器的一个新的配置或者创建新的(首领Sentinel,负责故障转移),配置会和配置纪元一起固话到硬盘中,这意味着停止和重启Sentinel进程是安全的。
Redis Sentinel是严重依赖于计算机时间的:对于实例来说确认一个实例是否可用就是记录上次PING的正确响应时间,然后和当前时间进行比较来确认的。
然而如果计算机时间异常改变了,或则是计算机繁忙,或则是由于某些原因进程堵塞了Sentinel可能会出现一些异常的行为。
The TILT mode is a special "protection" mode thata Sentinel can enter when something odd is detected that can lower thereliability of the system. The Sentinel timer interrupt is normally called 10times per second, so we expect that more or less 100 milliseconds will elapsebetween two calls to the timer interrupt.
TILT模式是一种特殊的保护模式,这样一个Sentinel可以在一些奇怪的事情发生时进入状态来降低系统的可用性。Sentinel时钟中断通常来说会每一秒调用10次,因此我们可以明确在两次时钟中断之间有差不多100毫秒。
What a Sentinel does is to register the previous time thetimer interrupt was called, and compare it with the current call: if the timedifference is negative or unexpectedly big (2 seconds or more) the TILT mode isentered (or if it was already entered the exit from the TILT mode postponed).
Sentinel所做的就是记录上次调用时钟中断的时间,然后和当次调用比较,如果时间间隔是负的或则异常的大(2秒或更多)TILT模式就会启动(或者是已经进入TILT模式推迟的状态)
当Sentinel处于TILT模式时,会继续监控所有的事情,但是:
如果事情恢复正常超过30秒,TILT模式会退出。
注意,某种程度上TILT模式可以使用很多内核提供的monotonic clock api来代替。然而因为当前系统会回避进程只是挂起或长时间没有被执行器执行的情况,索引还不能确定这是一个好的解决方案。