目录

Redis Cluster & Sentinel

不使用 Redis Cluster 时,可以使用 Redis Sentinel [ˈsentɪn(ə)l] 提供高可用。 Redis Sentinel 还提供其他附带任务,例如监控、通知并充当客户端的配置提供程序。

High availability with Redis Sentinel

Sentinel 能力的完整列表

  • 监测。Sentinel 会不断检查您的主实例和副本实例是否按预期工作。
  • 通知。Sentinel 可以通过 API 通知系统管理员或其他计算机程序,其中一个受监控的 Redis 实例出现问题。
  • 自动故障转移。如果一个 master 没有按预期工作,Sentinel 可以启动一个故障转移过程,其中一个副本被提升为 master,其他额外的副本被重新配置为使用新的 master,并且使用 Redis 服务器的应用程序被告知要使用的新地址连接时。
  • 配置提供者。Sentinel 充当客户端服务发现的权威来源:客户端连接到 Sentinel 以请求负责给定服务的当前 Redis 主服务器的地址。如果发生故障转移,Sentinels 将报告新地址。
1
2
3
redis-sentinel /path/to/sentinel.conf
# or
redis-server /path/to/sentinel.conf --sentinel

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

  • 至少三个 Sentinel 实例才能进行稳健的部署。
  • 三个 Sentinel 实例应放置在被认为以独立方式发生故障的计算机或虚拟机中。
  • Sentinel + Redis 分布式系统不保证在故障期间保留已确认的写入,因为 Redis 使用异步复制。然而,有一些方法可以部署 Sentinel,使丢失写入的窗口仅限于某些时刻,而还有其他不太安全的方法来部署它。
  • 您的客户需要 Sentinel 支持。流行的客户端库支持 Sentinel,但不是全部。

SDOWN 和 ODOWN 故障状态

Redis Sentinel 有两种不同的宕机概念,一种称为 Subjectively Down(主观下线) condition (SDOWN),是给定 Sentinel 实例本地的宕机条件。另一种称为 Objectively Down(客观下线) condition (ODOWN),当足够多的Sentinels(至少配置参数 quorum 数量的被监控master)具有SDOWN条件时达到,并使用该 SENTINEL is-master-down-by-addr 命令从其他Sentinels获得反馈。

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

从 SDOWN 切换到 ODOWN 没有使用强共识算法,而只是一种八卦的形式:如果给定的 Sentinel 收到报告说在给定的时间范围内没有来自足够多的 Sentinel 的主服务器工作,则 SDOWN 被提升为 ODOWN。如果此确认稍后丢失,则清除该标志。

为了真正启动故障转移,需要使用实际多数的更严格的授权,但在未达到 ODOWN 状态的情况下不能触发故障转移。

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

然而 SDOWN 也有语义含义。例如,处于 SDOWN 状态的副本不会被执行故障转移的 Sentinel 选择提升。

Quorum /ˈkwɔːr.əm/ 法定人数

前面的部分展示了 Sentinel 监控的每个主节点都与配置的仲裁相关联。它指定需要就主服务器的不可达性或错误条件达成一致以触发故障转移的 Sentinel 进程的数量。

但是,在触发故障转移之后,为了真正执行故障转移,至少需要大多数 Sentinel 授权 Sentinel 进行故障转移。Sentinel 永远不会在存在少数 Sentinel 的分区中执行故障转移。

让我们试着让事情更清楚一点:

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

差异可能看起来很微妙,但实际上很容易理解和使用。例如,如果您有 5 个 Sentinel 实例,并且仲裁设置为 2,则一旦 2 个 Sentinel 认为主服务器不可访问,就会触发故障转移,但是两个 Sentinel 中的一个只有在它获得时才能进行故障转移至少来自 3 个 Sentinel 的授权。

相反,如果将 quorum 配置为 5,则所有 Sentinel 必须就主错误条件达成一致,并且需要所有 Sentinel 的授权才能进行故障转移。

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

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

Redis Cluster

Redis 集群目标 Redis Cluster 是 Redis 的分布式实现,在设计中具有以下目标,按重要性顺序排列:

高达 1000 个节点的高性能和线性可扩展性。没有代理,使用异步复制,并且不对值执行合并操作。 可接受的写入安全程度:系统尝试(以最大努力的方式)保留来自与大多数主节点连接的客户端的所有写入。通常有一些小窗口,其中已确认的写入可能会丢失。当客户端位于少数分区时,丢失已确认写入的 Windows 更大。 可用性:Redis 集群能够在大多数主节点可访问的分区中存活,并且每个不再可访问的主节点至少有一个可访问副本。此外,使用副本迁移,不再被任何副本复制的主节点将从被多个副本覆盖的主节点接收一个。

Redis Cluster 不支持像 Redis 的独立版本那样的多个数据库。我们只支持数据库0;该SELECT命令是不允许的。

密钥分配模型 集群的密钥空间被分成 16384 个槽,有效地为 16384 个主节点的集群大小设置了上限(但是,建议的最大节点大小约为 1000 个节点)。

集群中的每个主节点都处理 16384 个哈希槽的子集。当没有进行集群重新配置时(即哈希槽从一个节点移动到另一个节点),集群是稳定的。当集群稳定时,单个哈希槽将由单个节点提供服务(但是,服务节点可以有一个或多个副本,在网络分裂或故障的情况下将替换它,并且可以用于扩展可以接受读取过时数据的读取操作)。

用于将键映射到哈希槽的基本算法如下(阅读下一段以了解此规则的哈希标记例外):

HASH_SLOT = CRC16(key) mod 16384

配置处理、传播和故障转移

集群当前纪元

Redis Cluster 使用了一个类似于 Raft 算法“术语”的概念。在 Redis 集群中,该术语被称为 epoch,它用于为事件提供增量版本控制。当多个节点提供相互冲突的信息时,另一个节点就有可能了解哪个状态是最新的。

是currentEpoch一个 64 位无符号数。

在创建节点时,每个 Redis Cluster 节点(包括副本节点和主节点)都将其设置currentEpoch为 0。

每次从另一个节点接收到一个数据包时,如果发送者的纪元(集群总线消息头的一部分)大于本地节点纪元,currentEpoch则更新为发送者纪元。

由于这些语义,最终所有节点都会同意currentEpoch集群中的最大节点。

当集群的状态发生变化并且节点寻求协议以执行某些操作时,将使用此信息。

目前,这仅在副本提升期间发生,如下一节所述。基本上,纪元是集群的逻辑时钟,它指示给定的信息胜过具有较小纪元的信息。

配置时期

每个主机总是configEpoch在 ping 和 pong 数据包中通告它,以及一张通告它所服务的插槽集的位图。

configEpoch创建新节点时,在 master 中将其设置为零。

configEpoch在副本选举期间创建一个新的。试图替换失败的主节点的副本会增加它们的纪元并尝试从大多数主节点那里获得授权。当一个副本被授权时,configEpoch 会创建一个新的唯一且副本使用新的configEpoch.

正如下一节中所解释的,configEpoch当不同的节点声称不同的配置时(由于网络分区和节点故障而可能发生的情况),这有助于解决冲突。

副本节点也在configEpochping 和 pong 数据包中通告该字段,但在副本的情况下,该字段表示configEpoch其最后一次交换数据包时的主节点。这允许其他实例检测副本何时具有需要更新的旧配置(主节点不会向具有旧配置的副本授予投票)。

每次configEpoch对某个已知节点的更改,所有接收此信息的节点都会将其永久存储在nodes.conf 文件中。同样的情况也发生在currentEpoch值上。fsync-ed在节点继续其操作之前更新时,保证这两个变量被保存并保存到磁盘。

在故障转移期间使用简单算法生成的configEpoch值保证是新的、增量的和唯一的。

副本选举和推广

副本选举和提升由副本节点处理,在主节点的帮助下投票支持副本进行提升。FAIL从至少一个具有成为主节点的先决条件的副本的角度来看,当主节点处于状态时,就会发生副本选举。

当满足以下条件时,副本开始选举:

  • 副本的主节点处于FAIL状态。
  • 主服务器服务于非零数量的插槽。
  • 副本复制链接与主服务器断开连接的时间不超过给定时间,以确保提升的副本的数据相当新鲜。这个时间是用户可配置的。

为了被选举,副本的第一步是增加其currentEpoch计数器,并向主实例请求投票。

副本通过FAILOVER_AUTH_REQUEST向集群的每个主节点广播数据包来请求投票。然后它会等待最多两倍的时间来等待NODE_TIMEOUT回复到达(但总是至少等待 2 秒)。

一旦一个 master 投票给了一个给定的副本,并以 a 进行肯定答复FAILOVER_AUTH_ACK,它就不能再投票给同一 master 的另一个副本了NODE_TIMEOUT * 2。在此期间,它将无法回复同一主站的其他授权请求。这不是保证安全所必需的,但对于防止多个副本同时被选举(即使使用不同的副本)很有用configEpoch,这通常是不想要的。

副本会丢弃任何AUTH_ACK纪元小于currentEpoch发送投票请求时的回复。这确保了它不会计算用于先前选举的选票。

Once the replica receives ACKs from the majority of masters, it wins the election. 否则,如果在两次NODE_TIMEOUT(但总是至少 2 秒)内没有达到多数,则选举被中止,之后将再次尝试新的选举NODE_TIMEOUT * 4(并且总是至少 4 秒)。