去中心Redis-Cluster规范(四)-故障容忍

7 篇文章 0 订阅
6 篇文章 0 订阅

去中心Redis-Cluster规范(四)

本文翻译自官方文档

这篇翻译的精确度可能不足,建议读者参考原文进行阅读.

故障容忍

心跳和流言消息

Redis-Cluster节点间持续交换ping和pong数据包.这两种数据包具有相同的结构,并且都携带了重要的配置信息.只有消息类型字段是唯一的不同点.接下来我们会将ping和pong数据包统称为心跳(heartbeat)数据包.

通常节点发送ping数据包会出发接收节点使用pong数据包进行回复.然而这并不是必须的.节点也可以只发送pong数据包以发送自己的配置信息给其他节点,无须触发一次回复.这非常有用,例如可以用来尽快广播新配置.

通常一个节点会每秒钟ping一小部分随机节点,每个节点发送的ping数据包和收到的pong数据包是一个常量,无论集群中的节点数量有多少.

然而每个节点会确保ping所有其他的节点,如果这些节点在超过一半的NODE_TIMEOUT时间里,没有发送ping或者回复pong给自己.在超过NODE_TIMEOUT之前,节点会与另外的节点重建TCP连接以确保节点不会由于当前TCP连接存在问题而被认为不可达.

当NODE_TIMEOUT设置为一个较小的数字,且集群的节点数量非常大时,全局交换的消息数量可能非常大.因为在没半个NODE_TIMEOUT的周期内,没有最新配置信息的节点会ping所有的其他节点.

例如在一个100节点的集群中,NODE_TIMEOUT设置为60秒,每个节点会每30秒尝试发送99个ping消息,意味着美妙发送3.3个ping.乘以100个节点,也就是说在集群中每秒发送330个ping.

有一些方式可以降低消息的数量,然而目前没有发现Reids-Cluster失效检测所使用的带宽问题,所以到目前为止还是采用明显直接的设计.注意即时在上面的例子中,每秒交换330个数据包,最终也是分隔到100个不同的节点上,所以每个节点的通信流量是可以接受的.

心跳数据包内容

想所有的类型的数据包一样,ping和pong数据包含有一个头,另外ping和pong还包含一个特别的流言段(Gossip Section).

通用的头包含如下信息:

  • 节点ID,一个160位的伪随机字符串,这个字符串在节点首次创建时被分配,并且在节点的整个声明周期内保持不变.
  • 发送节点的currentEpoch(当前时代)和configEpoch(配置时代)字段,Redis-Cluster基于这两个字段来执行一个分布式算法(在后续的章节会详细解释).如果节点是从节点,则configEpoch是最后感知到的主节点的configEpoch.
  • 表示一个节点是主还是从的节点标记,和其他单个位的节点信息.
  • 发送节点服务的hash slots的位图,或者如果节点是从节点,则这个位图表示它的主节点服务的hash slots.
  • 发送节点的基本TCP端口(redis用来接受客户端连接的端口,加上10000就是集群总线端口).
  • 从发送节点的视角观测到的集群状态(down或者ok)
  • 如果发送节点是从节点,会包含它的主节点ID.

ping和pong数据表还包含一个流言数据段.这个段落将发送节点视角观测集群中其他节点的信息告知接收节点.这个流言数据段只包含一小部分随机的发送节点知道的集群节点信息.流言数据段中提及的节点数量同比于集群的大小.

对每个节点来说,添加到流言数据段中的信息如下:

  • 节点ID
  • 节点的IP:PORT
  • 节点标记

流言数据段领接收节点获悉到发送节点看到的其他节点状态.这对失效检测和集群中的其他节点发现非常有用.

失效检测

Redis-Cluster失效检测是用来识别集群中的一个主或从节点被大部分节点不可达的情况的,此时会将一个从节点升级为主节点.如果从节点不能升级,集群将进入一个错误状态,停止接受来自客户端的请求.

前面已经提到过,每个节点都有一个与其他已知节点关联的标记列表.其中有两个PFAIL和FAIL是用于失效检测的.PFAIL意思是可能失效,是一种为确认的失效类型.FAIL表示一个节点正处于失效状态,这个状态是被集群中的大多数主节点在一个固定时间周期内确认的.

PFAIL flag :

当节点不可达超过NODE_TIMEOUT时间后,会被另外一个节点标记为PFAIL.主节点和从节点都可以标记其他节点为PFAIL,无论这个节点是什么类型.

对于一个Redis-Cluster节点来说不可达意味着活跃的ping超过NODE_TIMEOUT时间没有收到回复.要让这个机制有效NODE_TIMEOUT必须必网络的通信往返时间.为了增加正常操作期间的可靠性,当节点的发出的ping超过一半NODE_TIMEOUT后没收到回复,会尝试与其他节点重连.这个机制可以确保连接保持活跃,所以损坏的链接通常不会导致在节点间产生失效报告.

FAIL flag:

其他节点的PFAIL标记仅仅是一个节点的本地信息,不足以触发一次从节点升级.为了令一个节点被认为下线,PFAIL状态需要膨胀为FAIL状态.

在节点心跳的章节简单的提到,每个节点发送流言消息给其他每个节点,消息中包含一部分随机已知节点的状态.每个节点最终都会收到其他所有节点的标记(flag)集合.通过这种机制每个节点都可以通关处其他节点自己检测到的失效状态.

满足如下条件时,PFATIL状态会膨胀为FAIL状态:

  • 某个节点A发现另外一个被标记为PFAIL的节点B.
  • 节点A通过流言消息段获悉了集群中大多数主节点观测到的B节点状态.
  • 大多数主节点在NODE_TIMEOUT * FAIL_REPORT_VALIDITY_MULT时间内将B标记为PFAIL或FAIL.(在当前实现中有效的因子设置为2,所以这个时间就是2倍的NODE_TIMEOUT时间)

如果上面的条件都满足,则节点A会:

  • 标记节点B为FAIL
  • 发送FAIL消息给所有可达的节点.

FAIL消息会强制所有收到的节点标记节点B为FAIL状态,无论这个节点是否已经标记节点B为PFAIL状态.

注意FAIL标记几乎是单向的.意思是说一个节点可以从PFAIL变为FAIL,但是FAIL只能在一下情况下被清除:

  • 节点可达了且是个从节点.在这种情况下FAIL标记可以被清除,因为从节点不会执行失效转移.
  • 节点可达了且是个不提供任何slot服务的主节点.在这种情况下FAIL标记可以被清除,因为没有任何slot的主节点并不真正参与集群服务,仅仅是等待配置以加入集群.
  • 节点可达了且是个主节点,但是很长时间(N倍的NODE_TIMEOUT)没有检测到任何从节点升级.最好重新加入集群继续提供服务.

PFAIL-FAIL转换使用弱协商:

  1. 节点在一定周期内手机其他节点的检测结果,所以即使需要大多数节点同意,实际上收集到的状态是来自不同时刻不同节点的,我们不确定也不需要确定,在指定时刻大多数节点同意.然而我们会丢弃掉太旧的是失效报告,所以失效状态是由大多数节点在一个时间窗口内标记的.
  2. 每个节点检测到FAIL状态时都会使用FAIL消息强制设置其他节点,没有办法保证消息会达到所有节点.例如一个可能建的到FAIL状态的节点可能由于分区问题无法触达其他任何节点.

然而Redis-Cluster失效检测有一个活跃需求:最终所有节点应该统一给定节点的状态.有两种脑裂的情况.小部分节点相信节点处于FAIL状态,或小部分节点相信节点不处于FAIL状态.在这两种情况下,最终集群会对给定节点达成一致.

状况1:如果大部分主节点将一个节点标记为FAIL,由于失效检测和其产生的连锁反应,每个其他节点最终会标记这个主节点为FAIL,因为在指定的时间窗口内会报告足够的失效状态.

状况2:仅有小部分主节点标记一个节点为FAIL,从节点升级不会被触发并且每个节点最终会执行上面说的FAIL状态清除规则.

FAIL标记仅仅用来触发执行从节点升级算法的安全部分.理论上从节点可能独立行动,但主节点不可达时开始从节点升级,如果主节点实际上被大多数节点可达则会等待这些主节点拒绝提供确认.然后附加的复杂的PFAIL->FAIL状态转换,弱协商,还有在最短时间内集群的可达部分的FAIL消息强制状态传播具有实际的优势.由于这些机制,如果集群处于错误状态,通常所有节点会几乎同时停止接受写操作.这是使用Redis-Cluster的应用所期望的特性.同时避免了从节点由于本地问题导致不能触达主节点而尝试升级.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值