likes
comments
collection
share

redis架构系列——哨兵模式详解

作者站长头像
站长
· 阅读数 4

背景

一切的恐惧,且来源于火力不足 假如有人问题如下问题,你能回答上来吗?如果你能回答上来,那么你可以跳过本文。如何回答不了,本文将给你答案。

    1. redis哨兵模式下,网络策略只开哨兵端口可以吗?
    1. Redis哨兵模式的主要功能有哪些?
    1. Redis哨兵模式是如何进行故障检测的?
    1. Redis哨兵模式如何进行故障转移?
    1. Redis哨兵模式中,如何保证数据的一致性?
    1. Redis哨兵模式有哪些优缺点?

哨兵模式架构图

redis架构系列——哨兵模式详解

哨兵模式详解

功能

Sentinel 提供的功能:

  • 监控:Sentinel 会不断检查您的主实例和副本实例是否按预期工作。
  • 通知:Sentinel 可以通过 API 通知系统管理员或其他计算机程序,其中一个受监控的 Redis 实例有问题。
  • 自动故障转移:如果主服务器未按预期工作,Sentinel 可以启动故障转移过程,其中副本将提升为主服务器,将其他其他副本重新配置为使用新的主服务器,并使用 Redis 服务器的应用程序将收到连接时要使用的新地址的通知。
  • 配置提供程序:Sentinel 充当客户端服务发现的权限来源:客户端连接到 Sentinel 以请求负责给定服务的当前 Redis 主节点的地址。如果发生故障转移,Sentinels 将报告新地址。

Sentinel配置

Redis 源分配包含一个名为的文件,该文件是一个自记录的示例配置文件,可用于配置 Sentinel,但是典型的最小配置文件如下所示 以后: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

只需要指定要监视的主站,给每个单独的主站master(可以有任意数量的副本)不同的名称。没有需要指定自动发现的副本。Sentinel将更新使用有关副本的其他信息自动配置(在以便在重新启动时保留信息)。配置是在故障转移期间,每次将副本提升为主副本时,也会重写并且每次发现新的哨兵时。

上面的示例配置基本上监控了两组Redis实例,每个实例由一个主实例和未定义数量的副本组成。一组实例称为,另一组实例称为。mymasterresque 语句参数的含义如下:

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

第一行用于告诉Redis监视一个名为mymaster的master,即位于地址127.0.0.1和端口6379,仲裁为2。万事很明显,但仲裁参数: 仲裁是需要就无法访问主服务器这一事实达成一致的哨兵数量,以便真正将主服务器标记为失败,并在可能的情况下最终启动故障转移过程。

但是,仲裁仅用于检测故障。为了实际执行故障转移,需要将其中一个哨兵选为故障转移的领导者,并被授权继续。这只有在大多数Sentinel进程的投票中才会发生。

例如,如果您有5个Sentinel进程,并且给定的仲裁master设置为值2,这是发生的情况: 如果两个哨兵同时同意无法访问主节点,则两个哨兵中的一个将尝试启动故障转移。

如果总共至少有三个哨兵可访问,则故障转移将获得授权并实际启动。

实际上,这意味着在故障期间,如果大多数Sentinel进程无法通信(即少数分区中没有故障转移),则Sentinel永远不会启动故障转移

如何运行Sentinel

您可以运行 Sentinel 使用以下命令行:

redis-sentinel /path/to/sentinel.conf

否则,您可以直接使用edis-server启动它哨兵模式:

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

默认情况下,哨兵运行侦听与TCP端口26379的连接,因此要使Sentinels正常工作,必须打开服务器的端口26379才能接收来自其他Sentinel实例的IP地址的连接。否则,哨兵无法交谈,也无法就该做什么达成一致,因此会进行故障转移永远不会执行。

Sentinel本身被设计为在有多个Sentinel进程协同的配置中运行。让多个Sentinel进程协同工作的优势如下: 当多个Sentinel同意给定主节点不再可用时,将执行故障检测。这降低了误报的可能性。

即使并非所有Sentinel进程都正常工作,Sentinel也能正常工作,从而使系统能够抵御故障。毕竟,拥有一个本身就是单点故障的故障转移系统并没有什么乐趣。

Sentinel运行要求

  • 至少需要三个 Sentinel 实例才能实现可靠的部署
  • 这三个 Sentinel 实例应放置在被认为以独立方式发生故障的计算机或虚拟机中。例如,在不同的可用性区域上执行不同的物理服务器或虚拟机。
  • Sentinel + Redis 分布式系统不保证在故障期间保留已确认的写入,因为 Redis 使用异步复制。
  • 客户端需要 支持 Sentinel
  • Sentinel,Docker 或其他形式的网络地址转换或端口映射应谨慎混合使用:Docker 执行端口重新映射,中断其他 Sentinel 进程的 Sentinel 自动发现和主进程的副本列表。

Sentinel连接介绍

向 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"

它打印了有关主站的许多信息。有我们特别感兴趣的一些:

  • num-other-sentinels是2,所以我们知道哨兵已经为这个主节点检测到了另外两个哨兵。如果检查日志,将看到生成的事件。+sentinel
  • flags只是.如果主人倒下了,我们也可以在这里看到或标记。masters_downo_down
  • num-slaves正确设置为1,因此Sentinel还检测到存在附加到主副本的副本。 为了了解有关此实例的更多信息,您可能需要尝试以下操作两个命令:
# 提供有关连接到主人
SENTINEL replicas mymaster
# SENTINEL sentinels mymaster
SENTINEL sentinels mymaster

获取当前主站地址

Sentinel需要充当连接一组主服务器和副本的客户端,达到故障转移和重新配置的目的。通过以下命令实现:

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

添加或删除哨兵

添加

将新的Sentinel添加到您的部署是一个简单的过程,因为由Sentinel实现的自动发现机制。您需要做的就是启动配置为监视当前活动主节点的新Sentinel。在10秒内,哨兵将获得其他哨兵的列表,并且附加到主服务器的复制副本集。

如果需要一次添加多个哨兵,建议添加一个接一个,等待所有其他哨兵已经知道在添加下一个之前,关于第一个。这很有用,以便仍然保证多数只能在分区的一侧实现,在添加新哨兵的过程中应该发生故障。

删除

移除哨兵有点复杂:哨兵永远不会忘记已经看到的东西哨兵,即使他们长时间无法联系到,因为我们没有想要动态更改授权故障转移所需的多数,并且创建新的配置编号。所以为了删除哨兵在没有网络分区的情况下,应执行以下步骤:

  • 停止要删除的Sentinel的Sentinel进程。
  • 向所有其他Sentinel实例发送命令(如果您只想重置单个主实例,则可以使用确切的主实例名称)。一个接一个,在实例之间至少等待30秒。SENTINEL RESET **
  • 通过检查每个哨兵的输出,检查所有哨兵是否同意当前处于活动状态的哨兵数量。SENTINEL MASTER mastername

Sentinel 高级概念

SDOWN 和 ODOWN 故障状态

Redis Sentinel 有两种不同的宕机概念,一种称为 主观下降条件 (SDOWN),是 给定 Sentinel 实例的本地。另一个称为客观宕机条件 (ODOWN),当足够多的哨兵(至少 配置为受监控主站参数的编号)具有 SDOWN 条件,并使用 命令。quorumSENTINEL is-master-down-by-addr

哨兵和副本自动发现

哨兵与其他哨兵保持联系,以便相互联系检查彼此的可用性,并交换消息。然而,你不需要在每个Sentinel中配置其他Sentinel地址的列表实例,因为Sentinel使用Redis实例Pub/Sub功能为了发现监视同一主站的其他哨兵和副本。

此功能是通过向名为的通道发送hello消息来实现的。sentinel:hello

同样,您也不需要配置附加的副本列表到主节点,因为Sentinel会自动发现查询Redis的此列表。

每个Sentinel每两秒向每个受监控的主通道和副本Pub/Sub通道发布一条消息,使用ip、port、runid宣布其存在。sentinel:hello 每个Sentinel都订阅了每个主节点和副本的Pub/Sub通道,寻找未知的哨兵。当检测到新的哨兵时,它们将被添加为该主节点的哨兵。sentinel:hello

Hello消息还包括主设备的完整当前配置。如果接收Sentinel的给定主节点的配置早于接收的配置,则它会立即更新到新配置。

在将新哨兵添加到主节点之前,哨兵总是会检查是否已经存在具有相同符文标识或相同地址(ip和端口对)的哨兵。在这种情况下,将删除所有匹配的哨兵,并添加新的哨兵。

算法和内部结构

法定人数

Sentinel监控的每个主节点都与配置的仲裁相关联。它指定Sentinel进程数需要就主站的无法访问性或错误条件达成一致顺序触发故障转移。

但是,在触发故障转移后,为了实际执行故障转移,至少大多数哨兵必须授权哨兵故障转移。Sentinel从不在分区中执行故障转移,其中少数哨兵存在。 其中有一些概念要弄清楚:

  • 仲裁:需要检测错误条件才能将主节点标记为ODOWN的Sentinel进程数。
  • 故障转移由ODOWN状态触发。
  • 触发故障转移后,尝试故障转移的Sentinel需要请求对大多数Sentinel的授权(如果仲裁设置为大于多数的数字,则请求超过多数)。 这种差异可能看起来很微妙,但实际上很容易理解和使用。例如,如果您有5个Sentinel实例,并且仲裁设置为2,则一旦2个Sentinel认为无法访问主服务器,就会触发故障转移,但是,两个Sentinel中的一个只有在至少获得3个Sentinel的授权时才能进行故障转移。 相反,如果将仲裁配置为5,则所有哨兵必须就主错误条件达成一致,并且需要所有哨兵的授权才能进行故障转移。

这意味着仲裁可用于通过两种方式调整Sentinel:

  • 如果仲裁设置为小于我们部署的大多数Sentinel的值,我们基本上会使Sentinel对主节点故障更加敏感,即使只有少数Sentinel不再能够与主节点通信,也会触发故障转移。
  • 如果将仲裁设置为大于大多数哨兵的值,则仅当存在大量(大于大多数)连接良好的哨兵同意主哨兵关闭时,我们才会使哨兵能够进行故障转移。

配置纪元

哨兵需要获得多数人的授权才能开始故障转移有几个重要原因:

当Sentinel获得授权时,它将获得它正在故障转移的主节点的唯一配置周期。这是一个数字,用于在故障转移完成后对新配置进行版本控制。因为大多数人都同意将给定版本分配给给定的Sentinel,所以没有其他Sentinel能够使用它。这意味着每个故障转移的每个配置都使用唯一的版本进行版本控制。我们将了解为什么这如此重要。

此外,哨兵有一个规则:如果一个哨兵投票给另一个哨兵支持给定主节点的故障转移,它将等待一段时间来尝试再次对同一主节点进行故障转移。此延迟是您可以在中配置的。这意味着Sentinel不会尝试同时对同一个主服务器进行故障转移,第一个请求获得授权的人将尝试,如果失败,另一个将在一段时间后尝试,依此类推。2 * failover-timeoutsentinel.conf

RedisSentinel保证了活动属性,即如果大多数Sentinel能够通信,则最终将授权在主节点关闭时进行故障转移。

RedisSentinel还保证了每个Sentinel将使用不同的配置周期对同一主节点进行故障转移的安全属性。

配置传播

一旦Sentinel能够成功故障转移主节点,它将开始广播新配置,以便其他Sentinel更新其有关给定主节点的信息。

要使故障转移被视为成功,它要求Sentinel能够将命令发送到选定的副本,并且稍后在主副本的INFO输出中观察到切换到主副本。REPLICAOFNOONE

此时,即使正在进行副本的重新配置,故障转移也被视为成功,并且所有哨兵都需要开始报告新配置。

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

每个Sentinel都使用RedisPub/Sub消息在主节点和所有副本中持续广播其主节点配置版本。同时,所有哨兵都在等待消息,看看配置是什么由其他哨兵宣传。

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

由于每个配置都有不同的版本号,因此版本越大总是胜过较小的版本。

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

这意味着Sentinel保证了第二个存活属性:一组能够通信的哨兵将全部收敛到具有更高版本号的相同配置。

基本上,如果网络是分区的,每个分区都会收敛到更高的分区本地配置。在没有分区的特殊情况下,有一个分区,每个Sentinel都会同意配置。

客户端连接介绍

RedisSentinel使用“stats”或“cache”等名称标识每个主节点。每个名称实际上都标识了一组实例,由一个主实例组成以及可变数量的副本。

1. 连接到第一个Sentinel

客户端应循环访问Sentinel地址列表。对于每个地址,它都应该尝试连接到Sentinel,使用短超时(大约几百毫秒)。出现错误或超时时,应尝试下一个Sentinel地址。

如果尝试了所有Sentinel地址均未成功,则应向客户端返回错误。

应将第一个回复客户端请求的Sentinel放在列表的开头,以便在下次重新连接时,我们将首先尝试在上一次连接尝试中可访问的Sentinel,从而最大程度地减少延迟。

2. 询问Master节点地址

与Sentinel建立连接后,客户端应重试在Sentinel上执行以下命令:

SENTINEL get-master-addr-by-name master-name

其中master-name应替换为用户指定的实际服务名称。

此调用的结果可以是以下两个回复之一: 一个ip:port对。 空回复。这意味着Sentinel不认识这个主节点。 如果收到ip:port对,则应使用此地址连接到Redis主节点。否则,如果收到null回复,客户端应尝试列表中的下一个Sentinel。

3. 在目标实例中调用ROLE命令

一旦客户端发现了主实例的地址,它应该尝试与主服务器连接,并按顺序调用ROLE命令验证实例的角色是否真的是主实例。

如果ROLE命令不可用(它是在Redis2.8.12中引入的),客户端可能会求助于解析输出字段的命令。INFO replicationrole:

如果实例不是预期的主实例,则客户端应等待一小段时间(几百毫秒),并应从步骤1开始重试。

4. 处理重新连接

将服务名称解析为主地址并与Redis主实例建立连接后,每次需要重新连接时,客户端都应使用从步骤1重新启动的Sentinel再次解析地址。例如,在以下情况下,Sentinel应再次联系:

  • 如果客户端在超时或套接字错误后重新连接。
  • 如果客户端由于用户显式关闭或重新连接而重新连接。 在上述情况以及客户端与Redis服务器失去连接的任何其他情况下,客户端应重新解析主地址。

参考文章