算法高级(18)-Redis Cluster选举机制

Redis集群是一个distribute、fault-tolerant的Redis实现,主要设计目标是达到线性可扩展性、可用性、数据一致性。

一、一些特性

线性拓展 官方推荐最大的节点数量为1000,由于Cluster架构中无Proxy层,Master与Slave之间使用异步replication。

数据一致性 客户端容忍一定程度的数据丢失,集群尽可能保存Client write操作的数据,保证数据一致性。

可用性 Redis集群通过partition来提供一定程度的可用性,当集群中的一部分节点失效或者无法进行通讯时,集群仍可以继续提供服务。

  • 只要集群中大多数Master可达、且失效的Master至少有一个Slave可达,即集群非Fail状态,集群都是可用的。
  • Redis集群的replicas migration机制可以将拥有多个Slave的Master的某个Slave,迁移到没有Slave的Master下,即Slave分布相对平衡,确保Master都有一定数量的Slave备份。

集群节点属性 集群中每个Master node负责存储数据、集群状态,包括slots与nodes对应关系。Master nodes能够自动发现其他nodes,检测failure节点,当某个Master节点失效时,集群能将核实的Slave提升为Master。

Keys分布模型 集群的键空间被分割为16384个slots(即hash槽),slot是数据映射的基本单位,即集群的最大节点数量是16384(官方推荐最大节点数量为1000个左右)。集群中的每个Master节点负责处理16384个hash槽其中的一部分,当集群处于“stable”状态时(无slots在节点间迁移),任意一个hash slot只会被单个node所服务。以下是键映射到hash槽的算法:

HASH_SLOT = CRC16(key) mod 16384 

数据一致性保证 Redis集群尽可能保证数据的强一致性,但在特定条件下会丢失数据,原因有两点:异步replication机制以及network partition。

  • Master以及对应的Slaves之间使用异步的机制,在节点failover后,新的Master将会最终替代其他的replicas:
    • write命令提交到Master,Master执行完毕后向Client返回“OK”,但由于一部分replication,此时数据还没传播给Slave;如果此时Master不可达的时间超过阀值,此时集群将触发对应的slave选举为新的Master,此时没有replication同步到slave的数据将丢失。 
  • 在network partition时,总有一个窗口期(node timeout)可能会导致数据丢失:
    • 由于网络分区,此时master不可达,且Client与Master处于一个分区,且此时集群处于“OK”。此时Failover机制,将其中一个Slave提升为新的Master,等待网络分区消除后,老的Master再次可达,此时节点被切换为Slave,而在这段期间,处于网络分区期间,Client仍然将write提交到老的Master,因为该Master被认为是仍然有效的。当老的Master再次加入集群,被切换成Slave后,这些数据将永远丢失。

集群可用性 上述谈到多次集群状态的概念,那集群什么时候处于“OK”,什么时候处于“FAIL”,节点什么时候可用等,详见下面的解释: 当NODE_TIMEOUT时,触发failover,此时集群仍然可用的前提是:“大分区”(相对发生网络分区的Client-Master小分区端而言)端必须持有大部份Masters,且每个不可达的Master至少有一个Slave也在“大分区”端,且集群在小部分Nodes失效后仍然可以恢复有效性。举个例子:

集群有N个Master,且每个Master都有一个Slave,那么集群的可用性只能容忍一个Master节点被分区隔离,也就是说只有一个Master处于小分区端,当第二个Master节点被分区隔离之前扔保持可用性的概率为1-(1 /(N*2-1)),这里的意思是:当第一个节点失效后,剩余N*2-1节点,此时没有Slave的Master失效的概率为1 /(N*2-1)。比如有10个节点,每个Master有一个Slave,当2个nodes被隔离或失效后,集群可用性的概率是:1/(10*2-1)=5.26%,此时集群不再可用。
 

为了避免上述情况发生,Redis Cluster提供了“replicas migration”机制,当Master节点发生failover后,集群会动态重新分配、平衡Slaves的分布,有效地提高了集群的可用性。

二、从节点选举逻辑

  1. 节点是已下线Master对应的Slave
  2. FAIL状态的Master负责的hash slot 非空
  3. 主从节点之间的replication link断线的时长不能超过NODE_TIMEOUT * REDIS_CLUSTER_SLAVE_VALIDITY_MULT

当slave发现自己的master变为FAIL状态时,便尝试进行Failover,以期成为新的master。由于挂掉的master可能会有多个slave,从而存在多个slave竞争成为master节点的过程, 其过程如下:

  1. slave发现自己的master变为FAIL
  2. 将自己记录的集群currentEpoch加1,并广播FAILOVER_AUTH_REQUEST信息
  3. 其他节点收到该信息,只有master响应,判断请求者的合法性,并发送FAILOVER_AUTH_ACK,对每一个epoch只发送一次ack
  4. 尝试failover的slave收集FAILOVER_AUTH_ACK
  5. 超过半数后变成新Master
  6. 广播Pong通知其他集群节点。

从节点并不是在主节点一进入 FAIL 状态就马上尝试发起选举,而是有一定延迟,一定的延迟确保我们等待FAIL状态在集群中传播,slave如果立即尝试选举,其它masters或许尚未意识到FAIL状态,可能会拒绝投票。

延迟计算公式: DELAY = 500ms + random(0 ~ 500ms) + SLAVE_RANK * 1000ms

SLAVE_RANK表示此slave已经从master复制数据的总量的rank。Rank越小代表已复制的数据越新。这种方式下,持有最新数据的slave将会首先发起选举(理论上)。

跳转重定位

当客户端向一个错误的节点发出了指令,该节点会发现指令的 key 所在的槽位并不归自己管理,这时它会向客户端发送一个特殊的跳转指令携带目标操作的节点地址,告诉客户端去连这个节点去获取数据。客户端收到指令后除了跳转到正确的节点上去操作,还会同步更新纠正本地的槽位映射表缓存,后续所有 key 将使用新的槽位映射表。

[root@localhost 8001]# /usr/local/redis/redis-5.0.2/src/redis-cli -c -h 192.168.5.100 -p 8003
192.168.5.100:8003> get name
-> Redirected to slot [5798] located at 192.168.5.100:8002
"xxx"
192.168.5.100:8002> 

三、集群可视化工具

CodisManager、RedisPlus

四、总结

Redis集群为了解决什么问题而存在的? 解决线性可扩展性。

Redis集群诞生以前怎么解决这个问题? 客户端分片、代理协助分片(Twemproxy)、查询路由、预分片、一致性哈希、客户端代理/转发等。

Redis集群采用什么方式保证线性可扩展性、可用性、数据一致性? Hash槽、查询路由、节点互联的混合模式。

Redis集群化面临的问题是什么? Redis集群本身要解决的是可伸缩问题,同时数据一致、集群可用等一系列问题。前者涉及到了节点的哈希槽的分配(含重分配),节点的增删,主从关系指定与变更(含自动迁移)这些具体的交互过程;后者则是故障发现,故障转移,选举过程等详细的过程。

Redis集群实现的核心思想和思路是什么? 通过消息的交互(Gossip)实现去中心化(指的是集群自身的实现,不是指数据),通过Hash槽分配,实现集群线性可拓展。


我的微信公众号:架构真经(id:gentoo666),分享Java干货,高并发编程,热门技术教程,微服务及分布式技术,架构设计,区块链技术,人工智能,大数据,Java面试题,以及前沿热门资讯等。每日更新哦!

参考资料:

  1. https://segmentfault.com/p/1210000009708869/read
  2. https://www.jianshu.com/p/e6894713a6d5
  • 3
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

十步杀一人_千里不留行

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值