Redis哨兵译文

原文地址:https://redis.io/topics/sentinel

Redis哨兵文档

Redis Sentinel为Redis提供高可用性。实际上,这意味着使用Sentinel可以创建一个Redis部署,在没有人为干预的情况下抵抗某些类型的故障。

Redis Sentinel还提供其他附属任务,如监视,通知和作为客户端配置提供者。

这是在宏观层面上的Sentinel功能的完整列表(即大图):

  • 监测。Sentinel会不断检查您的主从实例是否按预期工作。
  • 通知。Sentinel可以通过API通知系统管理员、另一台计算机程序,在其中一个受监控的Redis实例出现问题时。
  • 自动故障转移。如果主服务器无法按预期工作,则Sentinel可以启动故障切换进程,其中从服务器升级为主服务器,其他附加从服务器将重新配置为使用新主服务器,并且使用Redis服务器的应用程序会在连接时被通知使用新地址。
  • 配置提供者。Sentinel充当客户端服务发现的权威来源:客户端连接到Sentinels以请求负责给定服务的当前Redis主服务器的地址。如果发生故障转移,Sentinels将报告新地址。

哨兵的分布式性质

Redis Sentinel是一个分布式系统:

Sentinel本身被设计为在多个Sentinel进程合作的配置中运行。多个Sentinel进程合作的优势如下:

  1. 当多个Sentinels同意给定的主服务器不再可用时,会执行故障检测。这降低了误报的可能性。
  2. 即使不是所有的Sentinel进程都能正常工作,Sentinel也能正常工作,从而使系统在发生故障时更具有健壮性,毕竟,有一个自身是单点故障的故障切换系统是没有意义的。

Sentinel,Redis实例(主设备和从设备)以及连接到Sentinel和Redis的客户端的总和也是具有特定属性的巨大的分布式系统。在本文档中,概念将逐步引入,从为了理解Sentinel的基本属性所需的基本信息,到更复杂的信息(可选),以便了解Sentinel的工作原理。

快速开始

获得哨兵

当前版本的Sentinel被称为Sentinel 2。它是使用更强大和更简单的预测算法(在本文档中进行了解释)重写了最初的Sentinel实现。

自Redis 2.8发布以来,Redis Sentinel的稳定版发布。

新的发展是在不稳定的分支中进行的,并且一旦它们被认为是稳定的,新功能有时会被移回到最新的稳定分支。

Redis Sentinel版本1与Redis 2.6一起提供,已弃用,不应使用。

运行哨兵

如果您使用的是redis-sentinel可执行文件(或者如果您的redis-server可执行文件具有该名称的符号链接),则可以使用以下命令行运行Sentinel:

redis-sentinel /path/to/sentinel.conf

否则,您可以以Sentinel模式直接使用redis-server可执行文件启动:

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

两种方式都是一样的。

但是,在运行Sentinel时必须使用配置文件,因为系统将使用此文件来保存当前状态,以便在重新启动时重新加载。如果没有给出配置文件或者配置文件路径不可写,Sentinel会拒绝启动。

默认情况下,哨兵运行监听连接到TCP端口26379,因此为了使Sentinel能够工作,服务器的端口26379必须处于打开状态才能接收来自其他Sentinel实例的IP地址的连接。否则哨兵之间不会交互,也不会同意做什么,所以故障切换永远不会执行。

在部署前了解有关Sentinel的基本知识

  1. 您需要至少三个Sentinel实例才能实现可靠的部署。
  2. 三个Sentinel实例应放置在认为独立失败的计算机或虚拟机中。例如,不同的物理服务器或虚拟机在不同的可用区域上执行。
  3. 由于Redis使用异步复制,Sentinel + Redis分布式系统不能保证在故障期间保留已确认的写入。然而,有些方法可以部署Sentinel,使窗口可以丢失局限于某些时刻的写入,而另外还有其他安全性较低的部署方式。
  4. 您的客户需要支持Sentinel。受欢迎的客户端库支持Sentinel,但不是全部。
  5. 如果您不在开发环境中进行不定期测试,或者在生产环境中更好(如果可行),那么就没有安全的HA设置。你可能有一个错误的配置,很晚(凌晨3点,当你的主服务器停止工作时)才会显现出来。
  6. Sentinel,Docker或其他形式的网络地址转换或端口映射应该小心:Docker执行端口重新映射,打破其他Sentinel进程的Sentinel自动发现以及主服务器的slave列表。有关更多信息,请查看本文后面有关Sentinel和Docker的部分。

配置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

您只需指定要监控的主设备,并为每个分离的主设备(可能有任意数量的从设备)指定不同的名称。不需要指定自动发现的从设备。Sentinel将自动更新配置,并提供有关从设备的附加信息(以便在重新启动时保留信息)。每次在故障转移期间将每个从属设备提升为主设备时,每次发现新的Sentinel时,都会重新配置该配置。

上面的示例配置主要监视两组Redis实例,每个实例由一个主节点和一个未定义数量的从节点组成。一组实例称为mymaster,另一组是resque。

哨点监控语句参数的含义如下:

sentinel monitor <master-group-name> <ip> <port> <quorum>

为了清楚起见,让我们逐行检查配置选项的含义:

第一行用于告诉Redis监控名为mymaster的主服务器,即地址127.0.0.1和端口6379,quorum为2。一切都非常明显,但是quorum参数:

  • quorum是需要就master无法访问的事实达成一致的哨兵的数量,以便真正标记slave失败,并最终在可能的情况下启动故障切换过程。
  • 然而,quorum仅用于检测失败。为了实际执行故障转移,Sentinels中的一个需要被选为故障转移的负责人并被授权继续。这只会发生在大多数Sentinel进程的投票中。

例如,如果您有5个Sentinel进程,并且给定主机的quorum设置为2,则会发生以下情况:

  • 如果两个哨兵同时同意master无法到达,那么其中一人将尝试启动故障切换。
  • 如果总共有三个可用的Sentinels,则故障切换将被授权并且将实际启动。

实际上,这意味着在故障期间,如果大多数Sentinel进程无法通信(在少数分区中没有故障切换),则Sentinel从不启动故障切换。

其他哨兵选项

其他选项几乎总是以下面的形式:

sentinel <option_name> <master_name> <option_value>

并用于以下目的:

  • down-after-milliseconds是以毫秒为单位的一个实例不可达的时间(或者不回应我们的PING,或者是回复一个错误),Sentinel开始认为它已关闭。
  • parallel-syncs设置可在同一时间进行故障转移后重新配置为使用新主节点的从节点数量。数字越小,完成故障转移过程需要的时间就越多,但是如果从服务器配置为服务旧数据,则可能不希望所有从服务器与主服务器同时重新同步。虽然复制过程对于slave而言通常是非阻塞的,但有时它会停止从master加载批量数据。通过将此选项设置为1,您可能需要确保一次只有一个slave无法访问。

其他选项在本文档的其余部分进行了描述,并在Redis发行版附带的示例sentinel.conf文件中进行了说明。

使用SENTINEL SET命令可以在运行时修改所有配置参数。有关更多信息,请参阅在运行时重新配置Sentinel部分。

示例Sentinel部署

现在您已经了解了有关Sentinel的基本信息,您可能想知道应该在哪里放置Sentinel进程,需要多少Sentinel进程等等。本节将展示一些示例部署。

我们使用ASCII艺术为了向您展示图形格式的配置示例,这就是不同符号的含义:

+———————+
| 这是一台独立运 |
| 行的计算机或虚 |
| 拟机。我们称之 |
| 为“盒子”             |
+———————+

我们在盒子中写下他们正在运行的内容:

+———————–+
| Redis master M1  |
| Redis Sentinel S1 |
+———————–+

不同的盒子通过线连接,以表明他们可以通话:

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

网络分区显示为使用斜杠的中断行:

+————–+                     +————-+
| Sentinel S1 |—— // ——| Sentinel S2 |
+————–+                     +————-+

另请注意:

  • masters被称为M1,M2,M3,…,Mn。
  • slaves被称为R1,R2,R3,…,Rn(R代表副本)。
  • sentinels被称为S1,S2,S3,…,Sn。
  • clients被称为C1,C2,C3,…,Cn。
  • 当一个实例由于Sentinel动作而改变角色时,我们把它放在方括号内,所以[M1]意味着一个由于Sentinel干预而成为master的实例。

请注意,我们永远不会在仅使用两个Sentinel的情况下显示设置,因为Sentinels总是需要与大多数Sentinel实例交谈才能启动故障切换。

例1:只有两个哨兵,不要这样做

+—-+         +—-+
| M1 |——–| R1 |
| S1  |         | S2 |
+—-+         +—-+

Configuration: quorum = 1

  • 在这种设置中,如果主设备M1出现故障,由于两个Sentinels可以就故障达成一致(显然quorum设置为1),并且还可以授权故障切换,因为多数设备是两台,所以R1将被升级。所以表面上它可以简单的工作,但请检查下面的几点,看看为什么这个设置被打破。
  • 如果M1正在运行的盒子停止工作,S1也停止工作。在另一个盒子S2中运行的Sentinel将无法授权故障转移,因此系统将无法使用。

请注意,多数是需要的为了排序不同的故障转移,并且稍后将最新配置传播到所有Sentinels。还要注意,在没有任何协议的情况下,在上述设置的单一层面进行故障转移的能力是非常危险的:

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

在上述配置中,我们以完全对称的方式创建了两个主设备(假设S2可以未经授权进行故障切换)。客户端可能会无限期地写操作到双方,并且无法了解分区何时恢复正确的配置,以防止永久脑裂的状况。

所以请至少在三个不同的盒子中至少部署三个哨兵。

示例2:带有三个盒子的基本设置

这是一个非常简单的设置,它具有调整附加安全性的简单优点。它基于三个盒子,每个盒子同时运行Redis进程和Sentinel进程。

           +—-+
           | M1 |
           | S1 |
           +—-+
               |
+—-+      |     +—-+
|  R2 |—-+—-| R3 |
|  S2 |            | S3 |
+—-+            +—-+

Configuration: quorum = 2

如果主设备M1出现故障,则S2和S3将就故障达成一致,并将授权故障切换,使客户端能够继续。

在每个Sentinel设置中,如果Redis被异步复制,总会有丢失一些写入的风险,因为给定的确认写入可能无法到达被提升为主设备的从设备。但是,在上述设置中,由于客户端与旧master分开,因此存在较高的风险,如下图所示:

              +—-+
              | 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实例在充当主服务器时,如果至少有一个从服务器无法写入,则会停止接受写入。由于复制是异步的,不能写入实际上意味着从机或者断开连接,或者没有发送超过指定的最大滞后秒数的异步确认。

使用这种配置,上例中的旧Redis主M1将在10秒后变为不可用。当分区愈合时,Sentinel配置将会聚合到新分区,客户端C1将能够获取有效的配置,并将继续使用新的主分区。

然而,没有免费的午餐。通过这种改进,如果两个从机关闭,主机将停止接受写入。这是一种折衷。

示例3:客户端盒子中的Sentinel

有时我们只有两个Redis盒子可用,一个用于master,一个用于slave。例2中的配置在这种情况下是不可行的,所以我们可以采取以下措施,将Sentinels放置在客户端:

       +—-+           +—-+
       | M1 |—-+—-| R1 |
       |       |     |      |       |
       +—-+     |      +—-+
                     |
    +————+————+
    |                |                |
    |                |                |
+—-+        +—-+        +—-+
| C1 |         | C2 |         | C3 |
| S1 |         | S2 |         | S3 |
+—-+        +—-+        +—-+

Configuration: quorum = 2

在此设置中,Sentinels的观点与客户端相同:如果大多数客户端都可以访问主服务器,则无问题。C1,C2,C3这里是通用客户端,并不意味着C1标识连接到Redis的单个客户端。它更像是一个应用程序服务器,一个Rails应用程序或类似的东西。

如果M1和S1运行的盒子出现故障,故障切换将会发生,但很容易发现不同的网络分区会导致不同的行为。例如,如果客户端和Redis服务器之间的网络将断开连接,则Sentinel将无法设置,因为Redis主服务器和从服务器都不可用。

请注意,如果C3与M1分区(上述网络几乎不可能,但更有可能使用不同的布局,或者由于软件层出现故障),我们遇到了类似于示例2中所述的问题,区别在于在这里我们没有办法打破这种对称性,因为只有一个从机和一个主机,所以主机在与从机断开连接时不能停止接受查询,否则在从机出现故障时主机将永远不可用。

所以这是一个有效的设置,但示例2中的设置具有诸多优点,例如Redis的HA系统与Redis本身运行在相同的盒子中,这可能更容易管理,并且能够限制时间量a掌握少数分区可以接收写入。

示例4:少于三个客户端的Sentinel客户端

如果客户端中没有足够的三个盒子(例如三个Web服务器),则示例3中描述的设置不能使用。在这种情况下,我们需要采取如下的混合设置:

+—-+           +—-+
| M1 |—-+—-| R1 |
| S1 |      |     | S2 |
+—-+     |     +—-+
              |
    +——+—–+
     |                |
     |                |
+—-+         +—-+
| C1 |          | C2 |
| S3 |          | S4 |
+—-+         +—-+

Configuration: quorum = 3

这与示例3中的设置类似,但我们在这四个框中运行了四个哨兵。如果主M1无法使用,其他三个Sentinels将执行故障切换。

从理论上讲,这个设置的工作原理是移除C2和S4正在运行的框,并将quorum设置为2。但是,我们希望Redis方面的HA不太可能在我们的应用程序层没有高可用性。

Sentinel,Docker,NAT和可能的问题

Docker使用一种叫做端口映射的技术:Docker容器中运行的程序可能会暴露在与程序认为使用的端口不同的端口上。这对于在同一服务器中同时使用相同端口运行多个容器很有用。

Docker不是唯一发生这种情况的软件系统,还有其他网络地址转换设置,其中端口可能会被重新映射,有时候不是端口,而是IP地址。

以两种方式重新映射端口和地址会导致Sentinel出现问题:

  1. 其他Sentinel的Sentinel自动发现不再有效,因为它基于hello消息,其中每个Sentinel都宣告他们正在监听连接的端口和IP地址。然而,哨兵无法理解地址或端口被重新映射,因此它宣布的信息对于其他Sentinel连接不正确。
  2. Slave以类似的方式在Redis master的INFO输出中列出:主机检测到TCP连接的远程对等端检测地址,而端口在握手过程中由从端自己公布,但端口可能是出于与第1点相同的原因是错误的。

由于Sentinel使用主设备INFO输出信息自动检测从设备,因此检测到的从设备将无法访问,并且Sentinel永远不能对主设备进行故障切换,因为从系统角度来看没有好的从设备,所以目前没有 除非您指示Docker映射端口1:1,否则您可以使用Sentinel监控与Docker一起部署的一组主从实例。

对于第一个问题,如果您想使用带有转发端口的Docker运行一组Sentinel实例(或任何其他端口被重新映射的NAT设置),您可以使用以下两个Sentinel配置指令来强制Sentinel公布一个特定的一组IP和端口:

sentinel announce-ip <ip>
sentinel announce-port <port>

请注意,Docker能够在主机联网模式下运行(请查阅–net = host选项以获取更多信息)。这应该不会造成任何问题,因为在此设置中不会重新映射端口。

快速教程

在本文档的下一部分中,所有关于Sentinel API,配置和语义的细节都将逐步介绍。然而,对于那些想要尽快使用该系统的人来说,本节将介绍如何配置3个Sentinel实例并与之交互。

这里我们假设实例在端口5000,5001,5002处执行。我们还假定您在端口6379上运行Redis主设备,并且从设备在端口6380上运行。我们将在处理期间的任何地方使用IPv4环回地址127.0.0.1 教程,假设你正在个人电脑上运行模拟。

三个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作为端口号。

有关以上配置的一些注意事项:

  • 主设备称为mymaster。它确定master及其slaves。由于每个主设备的名称不同,Sentinel可以同时监控不同的主设备和从设备集。
  • quorum被设置为2(哨兵监视器配置指令的最后一个参数)。
  • 毫秒后的数值是5000毫秒,即5秒,所以一旦我们在这段时间内没有收到我们的ping响应,master将被检测为失败。

一旦你启动了三个哨兵,你会看到他们登录的一些消息,如:

+monitor master mymaster 127.0.0.1 6379 quorum 2

这是一个Sentinel事件,如果您按照稍后指定的事件名称SUBSCRIBE,则可以通过发布/订阅接收这类事件。

在故障检测和故障转移期间,Sentinel会生成并记录不同的事件。

询问哨兵有关master的状态

使用Sentinel开始的最明显的事情是检查它正在监控的master是否工作得很好:

$ 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”

正如你所看到的,它会打印一些关于master的信息。有一些我们特别感兴趣的:

  1. num-other-sentinels是2,所以我们知道Sentinel已经为这个master检测到两个更多的哨兵。如果您检查日志,您将看到生成的+哨兵事件。
  2. 标识只是主人。如果主人关闭,我们可以期望在这里看到s_down或o_down标志。
  3. num-slave被正确设置为1,所以Sentinel也检测到有一个连接到我们主设备的从设备。

为了更多地了解这个实例,您可能需要尝试以下两个命令:

SENTINEL slaves mymaster
SENTINEL sentinels mymaster

第一个将提供有关连接到master的slave的类似信息,第二个则提供关于其他Sentinels的信息。

获取当前master的地址

正如我们已经指出的那样,Sentinel还可以作为想要连接到一组master和slave的客户端的配置提供程序。由于可能的故障转移或重新配置,客户端不知道谁是给定的一组实例的当前活动主服务器,所以Sentinel会导出一个API来问这个问题:

127.0.0.1:5000> SENTINEL get-master-addr-by-name mymaster
1) “127.0.0.1”
2) “6379”

测试故障转移

此时我们的玩具哨兵部署已准备好进行测试。我们可以杀死我们的master并检查配置是否改变。为此,我们可以这样做:

redis-cli -p 6379 DEBUG sleep 30

这个命令将使我们的mater不再可以到达,睡眠30秒。它基本上模拟了由于某种原因而挂起的master。

如果您检查Sentinel日志,您应该能够看到很多操作:

  1. 每个Sentinel都会通过+sdown事件检测到主服务器已关闭。
  2. 这个事件后来升级为+odown,这意味着多个Sentinels同意master无法访问。
  3. 哨兵投票支持将启动第一次故障转移尝试的哨兵。
  4. 故障转移发生。

如果您再次询问mymaster的当前主地址是什么,那么最后我们应该得到不同的回复:

127.0.0.1:5000> SENTINEL get-master-addr-by-name mymaster
1) “127.0.0.1”
2) “6380”

到目前为止很好……此时,您可以跳转到创建Sentinel部署,或者阅读更多内容来了解所有Sentinel命令和内部构件。

Sentinel API

Sentinel提供了一个API来检查其状态,检查受监控主设备和从设备的运行状况,订阅以获得特定通知,并在运行时更改Sentinel配置。

默认情况下,Sentinel使用TCP端口26379运行(请注意,6379是普通的Redis端口)。Sentinels使用Redis协议接受命令,因此您可以使用redis-cli或任何其他未修改的Redis客户端来与Sentinel交谈。

可以直接查询Sentinel来检查受监视的Redis实例的状态,从它的角度来看它知道的其他Sentinel,等等。或者,使用Pub / Sub,每次发生某些事件(如故障转移或进入错误条件的实例等)时,都可以从Sentinels接收推送形式的通知。

Sentinel命令

以下是接受命令的列表,不包括用于修改Sentinel配置的命令,稍后会介绍。

  • PING这个命令只是简单地返回PONG。
  • SENTINEL masters显示受监视的masters及其状态的列表。
  • SENTINEL master <master name> 显示指定master的状态和信息。
  • SENTINEL slaves <master name>显示该master的slave列表以及他们的状态。
  • SENTINEL sentinels <master name> 显示该master的哨兵实例列表及其状态。
  • SENTINEL get-master-addr-by-name <master name>用该名称返回主设备的IP和端口号。如果此主设备正在进行故障切换或成功终止,它将返回提升的从设备的地址和端口。
  • SENTINEL reset <pattern>该命令将重置所有具有匹配名称的主设备。模式参数是一个全局样式。重置进程清除主服务器中的任何先前状态(包括正在进行故障切换),并删除已发现并与主服务器关联的每个从服务器和标识符。
  • SENTINEL failover <master name>强制进行故障转移,就好像master无法访问一样,并且不要求与其他Sentinels达成一致(不过,将发布新版本的配置,以便其他Sentinels将更新其配置)
  • SENTINEL ckquorum <master name>检查当前的Sentinel配置是否能够达到故障切换master所需的quorum,并且大多数都需要授权故障切换。应该在监视系统中使用此命令来检查Sentinel部署是否正常。
  • SENTINEL flushconfig强制Sentinel重写它在磁盘上的配置,包括当前的Sentinel状态。通常情况下,Sentinel每次在其状态发生变化时都会重写配置(在重启时磁盘上保留的状态子集的上下文中)。但有时可能由于操作错误,磁盘故障,软件包升级脚本或配置管理器而导致配置文件丢失。在这些情况下,强制Sentinel重写配置文件的方法非常方便。即使以前的配置文件完全丢失,该命令也能正常工作。

在运行时重新配置Sentinel

从Redis版本2.8.4开始,Sentinel提供了一个API来添加,移除或更改给定主设备的配置。请注意,如果您有多个Sentinel,则应该将更改应用于您的所有实例,以便Redis Sentinel正常工作。这意味着更改单个Sentinel的配置不会自动将更改传播到网络中的其他Sentinels。

以下是用于更新Sentinel实例配置的SENTINEL子命令的列表。

  • SENTINEL MONITOR <name> <ip> <port> <quorum> 该命令通知Sentinel开始监视具有指定名称,IP,端口和quorum的新主服务器。它与sentinel.conf配置文件中的sentinel monitor配置指令相同,区别在于您不能在as ip中使用主机名,但需要提供IPv4或IPv6地址。
  • SENTINEL REMOVE <name> 用于移除指定的主设备:主设备将不再受监控,并且将完全从Sentinel的内部状态中移除,因此不再由SENTINEL主设备等列出。
  • **SENTINEL SET <name> <option> <value>**SET命令与Redis的CONFIG SET命令非常相似,用于更改特定master的配置参数。可以指定多个选项/值对(或根本没有)。所有可通过sentinel.conf配置的配置参数也可使用SET命令进行配置。

以下是SENTINEL SET命令的一个示例,用于修改名为objects-cache的主设备的down-after-milliseconds配置:

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

如前所述,SENTINEL SET可用于设置启动配置文件中可设置的所有配置参数 此外,可以只更改master quorum配置,而无需使用SENTINEL REMOVE和SENTINEL MONITOR删除和重新添加master数据,只需使用:

SENTINEL SET objects-cache-master quorum 5

请注意,没有等效的GET命令,因为SENTINEL MASTER以简单解析格式(作为字段/值对数组)提供所有配置参数。

添加或删除哨兵

由于Sentinel实施的自动发现机制,因此将新的Sentinel添加到您的部署是一个简单的过程。您需要做的就是启动新的Sentinel,配置为监视当前活动的master。在10秒内,哨兵将获得其他哨兵列表以及附属于master的slave集。

如果你需要一次添加多个Sentinel,建议一个接一个地添加它,等待所有其他Sentinels在添加下一个之前已经知道第一个。这对于仍然保证多数只能在分区的一侧实现是有用的,在添加新的Sentinels的过程中可能会发生失败。

这可以通过添加每个新的Sentinel并延迟30秒,并在网络分区不存在的情况下轻松实现。

在这个过程结束时,可以使用命令SENTINEL MASTER mastername来检查所有Sentinels是否同意Sentinel监视主设备的总数。

  1. 停止要删除的Sentinel的Sentinel进程。
  2. 将SENTINEL RESET *命令发送到所有其他Sentinel实例(如果您只想重置一个主设备,则可以使用确切的主设备名称而不是*)。一个接一个地等待实例间至少30秒。
  3. 通过检查每个Sentinel的SENTINEL MASTER mastername的输出,检查所有Sentinels是否同意当前活动的Sentinels的数量。

删除旧的master或无法访问的slave

哨兵永远不会忘记给定master的slave,即使他们长时间无法到达。这很有用,因为Sentinels应该能够在网络分区或故障事件后正确重新配置返回的slave。

而且,在故障转移之后,故障转移master实际上被添加为新master的slave,这样一旦它将再次可用,它将被重新配置为与新master一起复制。

然而,有时您想从Sentinels监控的slave列表中永远删除一个slave(可能是旧的master)。

为此,您需要向所有Sentinel发送SENTINEL RESET mastername命令:它们将在接下来的10秒内刷新slave列表,只添加从当前master INFO输出列出的正确复制的列表。

Pub / Sub消息

客户端可以使用Sentinel,因为它是与Redis兼容的Pub/Sub服务器(但不能使用PUBLISH),以便对通道进行SUBSCRIBE或PSUBSCRIBE并获得有关特定事件的通知。

频道名称与该事件的名称相同。例如,名为+sdown的频道将收到与进入SDOWN的实例有关的所有通知(SDOWN表示从您正在查询的Sentinel的角度来看,该实例不再可用)。

要获取所有消息,只需使用PSUBSCRIBE *进行订阅。

以下是您可以使用此API接收的频道和消息格式列表。第一个单词是通道/事件名称,其余是数据的格式。

注意:如果指定了实例详细信息,则表示提供了以下参数来标识目标实例:

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

标识master(从@参数到最后)的部分是可选的,只有当实例本身不是master时才被指定。

  • +reset-master <instance details> – master被重置。
  • +slave <instance details> – 检测到并附加了一个新的slave。
  • +failover-state-reconf-slaves &alt;instance details> – 故障切换状态已更改为reconf-slaves状态。
  • +failover-detected <instance details> – 检测到由另一个Sentinel或任何其他外部实体启动的故障转移(连接的slave变为master)。
  • +slave-reconf-sent <instance details> – 领导哨兵发送SLAVEOF命令到这个实例,以便重新配置它为新的slave。
  • +slave-reconf-inprog <instance details> – 正在重新配置的slave显示为新master ip:port对的slave,但同步过程尚未完成。
  • +slave-reconf-done <instance details> – slave现在与新master同步。
  • -dup-sentinel <instance details> – 指定master的一个或多个哨兵被重复删除(这发生在例如重启Sentinel实例时)。
  • +sentinel <instance details> – 检测并为这个master附加新哨兵。
  • +sdown <instance details> – 指定的实例现在处于主观下线状态。
  • -sdown <instance details> – 指定的实例不再处于主观下线状态。
  • +odown <instance details> – 指定的实例现在处于客观下线状态。
  • -odown <instance details> – 指定的实例不再处于客观下线状态。
  • +new-epoch <instance details> – 当前epoch已更新。
  • +try-failover <instance details> – 新的故障转移正在进行中,等待由多数选出。
  • +elected-leader <instance details> – 赢得指定epoch的选举,可以做故障转移。
  • +failover-state-select-slave <instance details> – 新的故障转移状态是select-slave:我们正在尝试找到适合提升的从属设备。
  • no-good-slave <instance details> – 没有好的slave可以提升。目前我们会在一段时间后尝试,但是在这种情况下,可能会改变状态机并终止故障切换。
  • selected-slave <instance details> – 我们找到了指定的好slave进行提升。
  • failover-state-send-slaveof-noone <instance details> – 我们正在尝试重新配置提升的slave作为master,等待它切换。
  • failover-end-for-timeout <instance details> – 故障转移因超时终止,slave最终将被配置为与新master进行复制。
  • failover-end <instance details> – 故障转移以成功结束。所有的slave似乎都被重新配置为与新master一起复制。
  • switch-master <master name> <oldip> <oldport> <newip> <newport> – 在配置更改后,master新IP和地址是指定的一个。这是大多数外部用户感兴趣的消息。
  • +tilt – tilt模式输入。
  • -tilt – tilt模式退出。

处理-BUSY状态

当Lua脚本运行的时间超过配置的Lua脚本时间限制时,-BUSY错误由Redis实例返回。在触发故障切换之前发生这种情况时,Redis Sentinel将尝试发送SCRIPT KILL命令,只有脚本是只读的,该命令才会成功。

如果在尝试之后实例仍然处于错误状态,它最终会失败。

slaves优先级

Redis实例有一个称为slave-priority的配置参数。这些信息在其INFO输出中由Redis slave实例公开,Sentinel使用它来从可用于故障切换为master的机器中挑选一个slave:

  1. 如果slave优先级设置为0,则slave永远不会升级为master。
  2. Sentinel首选优先级较低的从属设备。

例如,如果在当前master的同一个数据中心中有一个slave S1,而在另一个数据中心中有另一个slave S2,则可以将S1设置为优先级为10,S2设置为优先级为100,这样,如果master失败并且S1和S2都可用,则S1将是首选。

有关选择slave方式的更多信息,请检查本文档的slave选择和优先级部分。

Sentinel和Redis认证

当主设备配置为需要客户端密码时,作为安全措施,从设备还需要知道该密码,以便与主设备进行身份验证并创建用于异步复制协议的主从连接。

这是通过使用以下配置指令来实现的:

  • 在主服务器上设置requirepass以设置验证密码,并确保该实例不会处理未验证客户端的请求。
  • masterauth在slave为了与master认证为了正确地从master复制数据。

当使用Sentinel时,没有一个单一的主设备,因为在故障转移之后,从设备可能扮演主设备的角色,并且旧主设备可以重新配置以充当从设备,所以您想要做的是将上述指令设置为你所有的实例,无论是master还是slave。

这通常也是一个理智的设置,因为您不希望仅在主服务器中保护数据,从服务器中可以访问相同的数据。

但是,在您不需要身份验证即可访问的slave的罕见情况下,您仍然可以通过将slave优先级设置为零来执行此操作,以防止将此slave升级为master,并且仅在此slave中配置masterauth指令,而不使用requirepass指令,以便未经身份验证的客户端可以读取数据。

为了让sentinels在使用requirepass进行配置时连接到Redis服务器实例,Sentinel配置必须包含sentinel auth-pass指令,格式为:

sentinel auth-pass <master-group-name> <pass>

哨兵客户端实现

Sentinel需要明确的客户端支持,除非系统配置为执行将所有请求透明重定向到新的主实例(虚拟IP或其他类似系统)的脚本。Sentinel客户端指南中介绍了客户端库实现的主题。

更高级的概念

在下面的章节中,我们将介绍关于Sentinel如何工作的一些细节,而不是诉诸实现细节和算法,这些细节和算法将在本文档的最后部分介绍。

SDOWN和ODOWN故障状态

Redis Sentinel具有两种不同的关闭概念,一种称为主观下线状态(SDOWN),并且是对给定Sentinel实例而言是局部的下线状态。另一种称为客观下线状态(ODOWN),到达该状态当足够的Sentinels(至少配置为受监控的Master的Quorum参数)具有SDOWN条件并且使用SENTINEL is-master-down-by-addr命令从其他的Sentinels得到反馈。

从Sentinel的角度来看,如果在配置中指定为is-master-down-after-milliseconds参数的秒数的时间内它没有收到对PING请求的有效答复,则达到SDOWN条件。

对PING的可接受答复是以下情况之一:

  • PING用+ PONG回复。
  • PING用-LOADING错误回复。
  • PING用-MASTERDOWN错误回复。

任何其他答复(或根本没有答复)被认为无效。但请注意,在INFO输出中宣告自己为slave的逻辑master被视为下线。

请注意,SDOWN要求在整个配置的时间间隔内没有收到可接受的答复,例如,如果间隔为30000毫秒(30秒),并且我们每29秒收到一次可接受的ping答复,则认为实例正在工作。

SDOWN不足以触发故障转移:它仅意味着单个Sentinel认为Redis实例不可用。要触发故障转移,必须达到ODOWN状态。

要从SDOWN切换到ODOWN,不会使用强大的一致性算法,而只是一种gossip:如果给定的Sentinel获得报告说master在给定的时间范围内没有使用足够多的Sentinels,则将SDOWN提升为ODOWN。如果此确认稍后丢失,则该标志被清除。

为了真正启动故障转移,实际更严格的授权需要使用多数,但是如果没有达到ODOWN状态,则不会触发故障转移。

ODOWN条件仅适用于master。对于其他类型的实例,Sentinel不需要采取行动,因此slave和其他哨兵永远不会达到ODOWN状态,但只有SDOWN是。

但是,SDOWN也具有语义含义。例如,处于SDOWN状态的slave不会被Sentinel执行故障转移选择提升。

哨兵和slaves自动发现

哨兵与其他哨兵保持联系,以便相互检查彼此的可用性并交换消息。但是,您不需要在每个运行的Sentinel实例中配置其他Sentinel地址列表,因为Sentinel使用Redis实例的Pub / Sub功能来发现监视相同主设备和从设备的其他Sentinel。

该功能通过将hello消息发送到名为__sentinel __的通道实现:hello。

同样,您不需要配置连接到主服务器的从服务器列表,因为Sentinel会自动发现查询Redis的此列表。

  • 每个Sentinel都会向每个受监控的主/从通道发布消息__sentinel __:hello,每两秒钟通过ip,port,runid宣布其存在。
  • 每个哨兵订阅Pub / Sub频道__sentinel __:每个master和slave的hello,寻找未知的哨兵。当检测到新的哨兵时,它们将被添加为这个master的哨兵。
  • Hello消息还包含主设备的完整当前配置。如果接收的Sentinel具有比收到的旧master更早的配置,则会立即更新为新配置。
  • 在将新sentinel添加到master之前,Sentinel始终会检查是否已有一个具有相同runid或相同地址(IP和端口对)的sentinel。在这种情况下,所有匹配的哨兵都将被删除,并且添加新的。

故障转移过程之外的实例的Sentinel重新配置

即使没有进行故障转移,Sentinels也会尝试在受监视的实例上设置当前配置。特别地:

  • 声称为主设备的从设备(根据当前配置)将被配置为从设备,以便与当前主设备进行复制。
  • 连接到错误主设备的从设备将被重新配置为与正确的主设备一起复制。

对于Sentinels重新配置slave,必须观察一段时间的错误配置,即大于用于广播新配置的时间段。

这可以防止具有过时配置的Sentinels(例如因为它们刚刚从分区重新加入)将尝试在接收更新之前更改slave配置。

另请注意,始终尝试施加当前配置的语义如何使故障转移对分区更具抵抗性:

  • master失败后,他们返回可用重新配置为slave。
  • 在分区过程中分区的从节点一旦可达,就会重新配置。

关于本节要记住的重要一课是:Sentinel是一个系统,每个进程总是试图将最后的逻辑配置强加给一组被监控的实例。

slave选择和优先级

当Sentinel实例准备好执行故障转移时,由于主服务器处于ODOWN状态,并且Sentinel从已知的多数Sentinel实例收到故障转移授权,因此需要选择合适的从服务器。

slave选择过程评估有关slave的以下信息:

  • 与master断开连接的时间。
  • slave优先级。
  • 已处理的复制偏移量。
  • 运行ID。

发现与主设备断开连接的超过配置的主设备超时时间(down-after-milliseconds选项)十倍以上的从设备,以及从执行故障切换的Sentinel的角度来看主设备也不可用的时间, 被认为不适合故障转移并被跳过。

用更严格的术语来说,INFO输出建议与主设备断开连接超过以下条件的从设备:

(down-after-milliseconds * 10) + milliseconds_since_master_is_in_SDOWN_state

被认为是不可靠的,完全被忽视。

slave选择只考虑通过上述测试的slave,并按照以上标准对其进行排序,顺序如下。

  1. 按照Redis实例的redis.conf文件中配置的slave-priority对slave进行排序。较低的优先级将是优选的。
  2. 如果优先级相同,则检查slave处理的复制偏移量,并选择从master接收更多数据的slave。
  3. 如果多个slave具有相同的优先级并处理来自master的相同数据,则会执行进一步检查,从中选择具有字典上较小运行ID的slave。拥有较低的运行ID对于一个slave来说并不是一个真正的优势,但是为了使slave选择的过程更加确定,而不是诉诸于选择一个随机的slave是有用的。

Redis主设备(在故障转移后可能变成从设备)和从设备,如果有强烈优先选择的机器,则所有设备都必须配置slave-priority。否则,所有实例都可以使用默认运行ID运行(这是建议的设置,因为通过复制偏移量选择slave更有趣)。

Redis实例可以配置为特殊的slave-priority为零,以便Sentinels不会将其选为新master。但是,以这种方式配置的从属设备仍将由Sentinels重新配置,以便在故障转移后与新主设备进行复制,唯一的区别是它永远不会成为主设备。

算法和内部结构

在下面的章节中,我们将探讨Sentinel行为的细节。用户不需要了解所有细节,但对Sentinel的深入了解可能有助于更有效地部署和运行Sentinel。

Quorum

之前的部分显示,由Sentinel监控的每个master都与配置的quorum相关联。它指定了需要就master的不可达性或错误条件达成一致以便触发故障切换的Sentinel进程的数量。

但是,在故障转移被触发后,为了实际执行故障转移,至少多数Sentinels必须授权Sentinel进行故障转移。Sentinel从不在少数Sentinels存在的分区中执行故障转移。

让我们试着让事情更清楚些:

  • Quorum:为了将主人标记为ODOWN,需要检测错误情况的Sentinel进程的数量。
  • 故障转移由ODOWN状态触发。
  • 触发故障转移后,Sentinel尝试进行故障转移需要向多数Sentinel请求授权(如果Quorum设置为大于多数的数字,则需要超过多数)

差异可能看起来很微妙,但实际上很容易理解和使用。例如,如果您有5个Sentinel实例,并且Quorum设置为2,则一旦2个Sentinels认为master无法访问,则会触发故障切换,但是两个Sentinel中的一个只有在获得至少从3个哨兵授权故障切换时才能够进行故障切换 。

如果Quorum配置为5,则所有哨兵必须就master错误情况达成一致,并且需要来自所有哨兵的授权才能进行故障转移。

这意味着Quorum可以用两种方式调整哨兵:

  1. 如果将Quorum设置为小于我们部署的大多数哨兵的数值,我们基本上使得哨兵对于master失败更加明智,只要少数哨兵不再能够与master交谈就触发故障转移。
  2. 如果Quorum设置的值大于Sentinels的多数值,那么只有在Sentinel数量非常大(大于多数)的并且这些Sentinel同意master下线的情况下,Sentinel才能够进行故障转移。

配置epoch

哨兵需要从多数获得授权才能启动故障转移,原因如下:

当Sentinel获得授权时,它会为正在故障转移的主设备获取一个独特的配置epoch。这是在完成故障转移后将用于版本化新配置的编号。因为多数同意给定的版本被分配给给定的Sentinel,所以其他Sentinel将不能使用它 这意味着每个故障转移的每个配置都使用唯一版本进行版本控制。我们会明白为什么这是如此重要。

此外,哨兵有一个规则:如果一个哨兵投票给另一个哨兵作为给定master的故障转移,它将等待一段时间来尝试再次故障转移同一master。这个延迟是您可以在sentinel.conf中配置的failover-timeout。这意味着Sentinels不会同时尝试故障转移同一个主服务器,第一个要求被授权的服务器将尝试,如果失败,另一个服务器会在一段时间后尝试,等等。

Redis Sentinel保证活力属性,即如果大多数Sentinels能够通话,那么如果master下线,最终将授权故障转移。

Redis Sentinel还保证每个Sentinel将使用不同的配置epoch故障切换相同master的安全特性。

配置传播

一旦Sentinel能够成功故障切换成功,它将开始广播新的配置,以便其他Sentinels将更新关于给定master的信息。

要使故障转移成功,它需要Sentinel能够将SLAVEOF NO ONE命令发送到选定的slave,并且稍后在master的INFO输出中观察到master切换。

此时,即使正在重新配置slaves,故障转移也被认为是成功的,并且所有Sentinel都需要开始报告新的配置。

传播新配置的方式是我们需要每个Sentinel故障切换都使用不同版本号(配置epoch)进行授权的原因。

每个Sentinel都使用Redis Pub / Sub消息连续广播其master配置的版本,无论是在主节点还是在所有从节点中。同时所有的哨兵都在等待消息,看看其他哨兵宣传的配置是什么。

配置在__sentinel __:hello Pub / Sub频道中广播。

因为每个配置都有不同的版本号,所以更高的版本总是胜过较小的版本。

因此,举例来说,主mymaster的配置开始于所有Sentinels相信master在192.168.1.50:6379。此配置具有版本1。一段时间后,Sentinel有权使用版本2进行故障转移。如果故障转移成功,它将开始广播一个新配置,比如192.168.1.50:9000,版本为2。所有其他实例将看到此配置并相应地更新其配置,因为新配置的版本更高。

这意味着Sentinel可以保证第二个活跃属性:一组能够通信的Sentinel将全部聚合到具有更高版本号的相同配置。

基本上,如果网络被分区,每个分区将会汇集到更高的本地配置。在没有分区的特殊情况下,有一个单独的分区,每个Sentinel都会对配置达成一致。

分区下的一致性

Redis Sentinel配置最终是一致的,因此每个分区都会聚合到可用的更高配置。然而在使用Sentinel的真实系统中,有三种不同的角色:

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

为了定义系统的行为,我们必须考虑所有三个。

以下是一个简单的网络,其中有3个节点,每个节点运行一个Redis实例和一个Sentinel实例:

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

在这个系统中,原来的状态是Redis 3是master,而Redis 1和2是slave。发生分区隔离旧的master。哨兵1和2启动了故障转移,以促进哨兵1成为新的master。

Sentinel属性保证Sentinel 1和2现在拥有主设备的新配置。但是由于Sentinel 3位于不同的分区,因此Sentinel 3仍然保留旧的配置。

我们知道Sentinel 3在网络分区恢复时会更新其配置,但是如果有客户端与旧master分区,分区过程中会发生什么情况?

客户端仍然可以发送消息给Redis 3,这个旧的master。当分区重新加入时,Redis 3将变成Redis 1的从属设备,并且分区期间写入的所有数据都将丢失。

根据您的配置,您可能需要或不需要这种情况发生:

  • 如果您使用Redis作为缓存,则即使其数据将丢失,客户端B仍可能会很方便的写入旧的主服务器。
  • 如果您使用Redis作为存储,这不太好,您需要配置系统以部分防止此问题。

由于Redis是异步复制的,因此在这种情况下无法完全防止数据丢失,但是您可以使用以下Redis配置选项限制Redis 3和Redis 1之间的分歧:

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

通过上述配置(请参阅Redis发行版中的自我介绍的redis.conf示例以获取更多信息),Redis实例在充当主服务器时,如果至少有一个从服务器无法写入,则会停止接受写入。

由于复制是异步的,不能写入实际上意味着从机断开连接,或者没有发送超过指定的max-lag秒数的异步确认。

使用这种配置,上例中的Redis 3将在10秒后变得不可用。当分区愈合时,Sentinel 3配置将会聚合到新分区,并且客户端B将能够获取有效的配置并继续。

总的来说,Redis + Sentinel作为一个整体来说是一个最终一致的系统,合并函数是最后一次故障转移获胜,并且丢弃旧master的数据以复制当前master的数据,所以总是有一个窗口用于丢失已确认的写入。这是由于Redis异步复制和系统的“虚拟”合并功能的丢弃性质。请注意,这不是Sentinel本身的限制,如果您使用强一致的复制状态机协调故障转移,则相同的属性仍然适用。只有两种方法可以避免丢失已确认的写入:

  1. 使用同步复制(以及适当的一致性算法来运行复制的状态机)。
  2. 使用最终一致的系统,其中可以合并相同对象的不同版本。

Redis目前无法使用上述任何系统,并且目前超出了开发目标。但是,有些代理在Redis存储(如SoundCloud Roshi或Netflix Dynomite)之上实施解决方案“2”。

哨兵持久状态

Sentinel状态被保留在标记配置文件中。例如,每当收到一个新配置或创建(Leader Sentinels)时,对于一个master配置,该配置将与配置epoch一起保存在磁盘上。这意味着停止并重新启动Sentinel进程是安全的。

TILT模式

Redis Sentinel严重依赖计算机时间:例如,为了了解实例是否可用,它会记住最近一次成功回复PING命令的时间,并将其与当前时间进行比较以了解它的年龄。

但是,如果计算机时间以意想不到的方式发生变化,或者计算机非常繁忙,或者由于某种原因阻塞了进程,则Sentinel可能会以意想不到的方式开始运行。

TILT模式是一种特殊的“保护”模式,Sentinel可以在检测到可能降低系统可靠性的奇怪事件时进入该模式。Sentinel定时器中断通常每秒调用10次,所以我们预计在两次调用定时器中断之间会经过多于或少于100毫秒的时间。

Sentinel做的是在上次调用定时器中断时进行注册,并将其与当前调用进行比较:如果时间差为负值或意外大(2秒或更长),则进入TILT模式(或者它已经是从TILT模式进入退出模式)。

在TILT模式下,Sentinel将继续监视所有事物,但是:

  • 它完全停止行动。
  • 它开始对SENTINEL is-master-down-by-addr请求做出负面回应,因为检测失败的能力不再受信任。

如果在30秒内一切正常,TILT模式退出。

请注意,在某些方面,可以使用许多内核提供的单调时钟API来替换TILT模式。然而,由于当前的系统长时间处于暂停或未被调度程序执行的情况下避免了问题,所以还不清楚这是否是一个好的解决方案。

猜你喜欢

转载自blog.csdn.net/heroqiang/article/details/80052167
今日推荐