实习的时候在做redis相关的东西,3.0的stable版本还没有出,所以自己先做了一个redis cluster。后来发现3.0的进度变快了,所以也来学习一下官方的实现方法~以下是对官方文档集群实现中容错部分的解读。并没有翻译所有的内容,也不是句句对应。由于官方文档也在更新,所以我也会持续更新。
----现在redis 3.0的正式版已经出来了,基本的思路没有太大变化,有些概念定义的变化,会尽快补充。
第一次做这种文档整理,有错误欢迎指出!请轻拍>__<
Ping/pong
1. 在每一秒,一个节点会随机向一些节点发送ping包。(所以无论集群中有多少个节点,发出的ping包和接受的pong包是一个常数)
2. 每一个节点需要保证,对在一半的NODE_TIMEOUT时间以上仍然没有发送过ping包或者没有接受过pong包的节点发送ping包。
3. 在NODE_TIMEOUT到达之前,节点还可以试着与其他节点重新建立TCP连接,以避免因TCP连接问题造成的不可达。
4. 当NODE_TIMEOUT很小而节点数量很大的时候,每秒发送的信息数量是很大的。
a) 有一些可以减少这些信息数量的方法,不过因为现在的测试表明即使NODE_TIMEOUT很小,集群也能可靠地工作,所以暂时没有使用这些方法。
5. Ping/pong包的内容
a) Common header
i. 节点ID。160bit伪随机字符串。
ii. currentEpoch和configEpoch。
iii. node flag。说明主从以及其他一些single-bit信息
iv. hash slot和节点映射关系的位图。感觉应该是,发送者节点和它服务的hash slot。
v. port
vi. 集群的状态
vii. 如果是从的话,还有它的主的节点ID
b) Gossip section
发送者对于集群中一些随机节点的信息。对每一个节点都包括:
i. 节点ID
ii. IP和port
iii. Node flag。
Failure检测
1. 什么算failure?
a) 当一个master或者一个slave不能被大多数的节点所达的时候。
b) 此时整个集群都不会再接受客户端的请求。
2. 什么叫不可达?
a) 当一个节点向另一个节点发出ping包后,在NODE_TIMEOUT时间内没有收到pong回复。这里要求NODE_TIMEOUT的时间与网络往返的时间相比必须要足够大。同时,为了避免broken connection,节点会在0.5 * NODE_TIMEOUT的时间后,如果还没有收到pong回复,将重新连接另一个节点。
b) 默认为15s。
3. 每个节点都会保存着集群中所有节点的状态。状态分为PFAIL和FAIL。
a) PFAIL:Possiblefailure。
- 是一个未确认的失败状态。
- 当一个节点在NODE_TIMEOUT的时间内不可达。主和从都可以表示别的节点为PFAIL。
b) FAIL:当满足下列条件时:
- A把B标记为PFAIL
- A通过gossip信息从集群的大多数中获知其他节点对B的状态
- 大多数主节点在NODE_TIMEOUT * FAIL_REPORT_VALIDITY_MULT时间内发送PFAIL信号。
节点A将会把节点B标记为FAIL,并且对每个可达的节点发送FAIL的消息。
c) 可以清除FAIL标记的情况:
- 节点可达,且节点为从。
- 节点可达,且节点为主,且节点没有服务任何一个slot。
- 节点可达,且节点为主,但是在很长的一段时间(N * NODE_TIMEOUT)内都没有从代替它的位置。
4. 从PFAIL->FAIL的转化,使用了一个弱协议:
a) 每个节点从其它节点处拿到的信息是不同时间的,所以不能保证拿到的信息是稳定的
b) 不能保证把FAIL信息发给所有节点
5. 要求:最终所有的节点对状态都会有一个共同的认识,即使处于分隔状态,当它们一旦从分隔中恢复。
分隔造成的对FAIL的认识不同,是否影响?
- 如果是大多数把一个节点的状态标记为了FAIL,那么最终大家都会是FAIL。
- 如果只是一小部分把一个节点标记成了FAIL,那么slave选举将不会发生。当N * NODE_TIMEOUT的时间后还没有发生选举,那么FAIL标记会被清除。
EPOCH
1. currentEpoch
a) 用于给事件提供一个增加的版本号。如果多个节点提供了冲突的信息,那么currentEpoch可以帮助一个节点知道哪个状态是最新的。
b) 更新:当接收到ping或者pong包的时候,如果发送者的epoch比当前的高,那么当前节点的currentEpoch就会被更新为发送者的epoch。
c) 用于slave选举。
2. configEpoch
a) 用于化解不同节点声明背离的配置的冲突
b) 在ping和pong包中,含有节点和对应服务的slots的对应信息。configEpoch用于标识这些信息。
c) 当新节点创建时为零。当slave选举时,会产生新的configEpoch。最后赢得选举的slave会产生一个新的configEpoch。
d) Slave的configEpoch包括它的master的configEpoch和它们最近一次交换包的时间。
Slave选举和切换
1. Slave选举的发起的时候:
当一个master的至少一个具有变成master条件的从认为master的状态是FAIL的时候。
2. 发起需要满足的条件:
a) Slave的主是FAIL状态
b) Master在服务一些slots
c) Slave和master之间的连接断开还在一定时间之内
3. 选举步骤
a) Slave增加它的currentEpoch
b) Slave向集群中的每一个master节点发送一个FAILOVER_AUTH_REQUEST包,然后在2 *NODE_TIMEOUT的时间里等待回复。
c) 一旦一个master对一个slave进行了投票(回复了一个FAILOVER_AUTH_ACK包),那么它在NODE_TIMEOUT * 2的时间内不能再为属于这个Master的slave投票。这样能够避免多个slave同时被选举。
d) slave会丢弃掉比它发送请求时的currentEpoch小的AUTH_ACK。这样避免计算到上一次选举的投票。
e) 当一个slave获得了大多数的master的票,它就赢得了选举。否则如果没有在NODE_TIMEOUT * 2的时间内得到足够的回复,就会在NODE_TIMEOUT * 4的时间后重新发起选举。
4. 选举延迟
a) slave进行选举,会在master被标记为FAIL的一段时间之后。这样可以保证集群中的所有节点都知道这个master已经是FAIL状态了,而不会拒绝给这个slave投票。
b) 延迟:
i. DELAY = 500 MS + RANDOM DELAYBETWEEN 0 AND 500 MS + SLAVE_RANK * 1000 MS
ii. SLAVE_RANK: 拥有更新数据的slave进行选举的延迟会更少。
5. Epoch更新
当一个slave赢得了选举,它会把configEpoch设置为选举开始时它的currentEpoch。
6. 配置更新
a) 其他节点发现有一个新的节点在服务原来旧的master的数据,并且拥有一个更大的configEpoch,于是会更新配置。
b) 旧的master重启后会变为它的从
c) 其它从也变为它的从
d) 为了加速集群配置的更新,pong包将会发给可达的每一个节点(只有这里是这样么?)
7. 竞争条件
当出现分隔时,使用configEpoch判断。configEpoch更新的将会被选举为主。
例子:
一个master有三个slave A,B, C. 第一次A被选举为master,过会儿A被分隔。B被选举为master。过会儿B被分隔,同时A的分隔被修复。但是C的configEpoch会大一些,所以其它节点会更新其配置为C的配置。A发现C与它服务同样的槽,但是configEpoch更大,于是变成C的slave.
Master对slave选举请求的回复
1. Master投票时需要满足的条件:
a) master只会对大于它已经投票的epoch进行投票。它记录一个lastVoteEpoch的值,当投票时更新。
b) 当slave的master被标记为FAIL才投票
c) AUTH请求中的currentEpoch如果小于master的currentEpoch,那么会忽略这个请求。
d) Master不会在2 *NODE_TIMEOUT的时间内对属于同一个master的slave再投票。这样可以保证一个slave有很多的时间去通知大家,它已经赢得了选举。
e) Master不会试图去选举一个最好的slave。只要满足条件就会投。只是一般来说,最佳的slave会更早发起投票。
f) 当master拒绝对slave投票,不会有拒绝回复,只是忽略。
g) 如果申请投票的slave它的configEpoch比master表中任何一个它声明服务的slot的configEpoch要小,那么master就不会为它投票。
Replica migration
1. 目的:
增强可用性。
2. 基本思路
在配置的时候,给某些master配置多于一个的slave。于是当有的master挂机,只有一个slave的时候,可以把slave个数多于1的master的一个slave过继到这个新的master下面。这样如果新的master再次挂机,还有补救的机会。
3. 算法
a) 什么是好的slave
从当前节点来看不是FAIL状态
b) 触发时机
当slave发现有至少一个master没有任何好的slave
c) 哪些slave会成为被过继的
i. 拥有最多slave的master中的ID最小的slave
ii. 每个master满足割让条件时拥有的最小的slave的数量为用户配置的
d) 可能一次会有多个slave被过继,但是没有关系。如果这样导致出现新的没有slave的master,那么这个算法会被再次触发。
节点映射信息传播
1. 利用ping/pong传播。
2. 增加一个新的节点时,它自己的hash slot和节点的对应关系都是nil,也就是未分配的。
3. 传播的规则:
a) RULE1:如果有一个未分配的hashslot,并且有一个已知的节点声明拥有它,那么该节点就会把这个hash slot和那个节点关联起来。
b) RULE2:如果一个hashslot已经被分配了,但是有一个节点在声明它在使用一个比此前的hash slot的拥有者更大的configEpoch,那么该节点就会把这个hash slot和有更高configEpoch的节点关联起来。
UPDATE
1. 使用场景:当一个主被认为挂了之后,从替换它成为主,然后从也挂了。再之后主从网络分隔中恢复,于是主的configEpoch信息比此前从的configEpoch信息要低,但是没有任何复制操作来更新它的configEpoch。
2. 作用:当一个节点发现,某个别的节点正在以一个更低的configEpoch声明它在服务的slots时,就会发送UPDATE信息,包括这个新节点的ID和这个新节点的bitmap。