无论是主从复制,还是哨兵模式,都无法摆脱每个节点需要保存所有数据。为了实现水平扩展,Redis 在主从、哨兵保证高可用的基础上提出 Cluster 集群模式,通过 Cluster 集群模式实现真正意义上的水平扩展

Cluster 模式提出槽的概念,每个分片负责一部分槽,每组 redis 节点(master + slave)组成一个分片。客户端发出指令后,根据 key 计算它应该属于哪个分片、通过分片找到对应的 redis 节点,在对应节点执行相应命令完成客户端请求

每个槽并不只保存一对 key-value,如果将单节点理解为表的话,一个槽就相当于表的一个分区。Redis 默认有 16384 个哈希槽,也就有 16384 个表分区

其中 Cluster 模式架构图大概如下(图片摘自程序员囧辉):

cluster redis3 瘫痪 redis cluster status_cluster redis3 瘫痪


示例 Cluster 集群包含 3 个分片,每个分片包含 master、slave 两个节点,各分片负责约 5460 个槽

根据架构图可以看出,Cluster 集群模式具备以下特点:

  1. 去中心化,分片和分片之间关系对等,不存在主从之分。分片内部维护主从复制以及故障转移,保证高可用。一般情况下同一个分片的 master、slave 节点不会部署在同一个机房,保证某个机房出故障后,不会导致整个分片数据异常
  2. 对于每个 key ,根据 CRC16 算法确定槽位,通过槽位确定分片
  3. 所有 redis 节点互连,通过 PING - PONG 机制进行心跳检测
  4. 客户端与 Redis 节点直连即可,无需中间代理层。客户端不需要连接集群所有节点,连接某一个可用节点就行

redis cluster 有固定的 16384 个 hash slot,对每个 key 计算 CRC16 值,然后对 16384 取模,获取 key 对应的 hash slot。

每个节点都会记录哪些槽指派给了自己,哪些槽指派给了其它节点。对于客户端发送的命令,计算应该属于哪个槽。如果是自己负责,直接执行命令,否则返回客户端 MOVED 错误,指引客户端转向正确的节点

设计槽的另一个目的在于方便迁移:增加一个 master,就将其它 master 的 hash slot 移动部分过去,减少一个 master,就将它的 hash slot 移动到其它 master 上去


假设某个 master 节点故障后,需要从 slave 节点中选举出新的 master 节点,具体选举过程如下:

  1. 当 slave 节点发现 master 节点进入下线状态时发起选举:将 currentEpoch 加 1,并向集群广播消息 CLUSTERMSG_TYPE_FAILOVER_AUTH_REQUEST,要求所有收到这条消息、并具有投票权的节点向当前从节点投票
  2. 其它节点收到消息后,根据规则判断是否投票,判断成功返回消息 CLUSTERMSG_TYPE_FAILOVER_AUTH_ACK 消息,表示主节点同意当前从节点成为新的主节点
  3. 集群中所有从节点都可以参与选举,假设一共有 n 个主节点参与投票,只有获得票数超过 n / 2 + 1 的从节点才能成为主节点。由于每个主节点只能投票一次,因此最多只有有一个节点满足条件。如果不存在节点满足条件,则重新开始选举

其它节点根据如下条件判断是否投票给对应从节点:

  1. 如果当前节点是 slave,或者是 master 但是不负责处理槽,检验失败,不投票,没有投票权
  2. 请求节点的 currentEpoch 小于当前节点的 currentEpoch,检验失败,不投票。因为请求升主的 slave 节点状态与集群状态不一致
  3. 当前节点已经投过票,检验失败,不投票
  4. 请求节点是 master,检验失败,不投票
  5. 请求节点的 master 为空,检验失败,不投票
  6. 请求节点的 master 没有故障,并且不是手动故障转移,检验失败,不投票
  7. 上一次为该 master 的投票时间,在 cluster_node_timeout 的 2 倍范围内,检验失败,不投票。
  8. 请求节点宣称要负责的槽位 configEpoch 小于之前负责这些槽位的节点,检验失败,不投票

如果请求节点通过以上所有检验,那么主节点支持从节点成为新的主节点


Redis Cluster 集群通过 ASK 错误实现在线扩容:

在槽的迁移过程中若有客户端访问,首先访问源节点,如果从源节点自身数据库查到指定键,直接执行命令返回结果。如果没找到,说明该键已经迁移到新节点。源节点返回一个 ASK 错误,指引客户端转向正在导入槽的目标节点,并再次发送命令,获取结果


关于 Cluster 集群暂时先写到这里,后面继续补充。。。