redis cluster模式

经过前几章,咱们已经了解redis从单机版、高并发的主从架构和保证高可用的哨兵模式。可是主从架构的高并发是针对那些读远大于写的场景,若是要保证读和写都是高并发的场景呢?那就是能够使用redis集群模式。html

节点

redis集群模式一般是有多个redis节点组成。Redis服务器在启动时会根据cluster-enabled配置选项是否为yes来决定是否开启服务器的集群模式。node

# cluster-enabled yes
 cluster-enabled yes

当启动集群模式后,在集群中的每一个节点都会存在一个clusterState数据结构。这个结构记录了在当前节点的视角下,集群目前所处的状态,例如集群是在线仍是下线,集群包含多少个节点,集群当前的配置纪元等信息。以下图为node1的clusterState结构。web

image-20201117205849712

槽指派

在一个三个redis节点组成的redis集群中,当咱们往该集群写入一个命令,那这个命令会被写入到哪一个节点呢?redis

redis集群将整个数据库分为16384个槽(slot)。每一个redis节点负责其中一部分的槽,当16384个槽都有redis节点负责时,整个redis集群才能正常工做。算法

为啥是16384个槽(slot)数据库

参考博文数组

因此往redis集群写入一个命令后,当前节点经过CRC16(key)和&12384计算出一个位于1~16384之间的值,该值决定这对键值对属于哪一个槽。bash

命令写入

在redis每个节点中都保存在这个一个关于redis集群的clusterState结构,这个结构包含这个当前这个集群的相关信息,其中也包含着全部槽的指派信息。服务器

image-20201118212129185

如上图所示,在一个三个redis节点的集群中,每个redis节点都存在这clusterState信息。ClusterState结构中有slots属性,并指向一个大小为16384的redisNode数组。网络

命令写入的流程:

  1. 首先写入其中一个节点,该节点开始经过槽分配算法计算槽值M。
  2. 在slots属性中,redisNode[m]快速定位到该槽负责的节点。
  3. 判断负责的节点是否为本身,是执行命令,否返回moved命令(moved : )。该命令包含正确的节点的ip和端口号。
  4. 客户端接收到moved的错位信息,将命令发送到正确的节点。

槽维护

在起初全部槽没有被指派时,能够经过执行如下命令将一个或者多个槽指派当前执行该命令的redis节点。

# CLUSTER MEET <slot> [slot...]
CLUSTER MEET 0,1,2,3

槽信息会被保存在redisnode节点结构的slots和numslot属性中,其中slots是一个二进制数组大小为16383,该数组的索引正好对应16384个槽,值为0或1,1就表示该索引对应槽由当前redis节点负责;numslot记录当前redis节点负责的槽总数。

image-20201119203556528
image-20201119203556528

在一个集群的中redis节点会相互网络链接发送信息,并告知对方本身在负责哪些槽。其余redis节点收到信息后,会更新本身的clusterState结构信息,主要是包含所有槽信息的clusterState.slots属性和clusterState.nodes中对应节点的clusterNode.slots和numslot信息。所以每个redis节点中都保存在完整的槽节点指派信息。

image-20201119205629055
image-20201119205629055

从新指派

在三个节点的redis集群,当要给该集群在增长一个节点node4时,槽在已被所有分配,可是node4须要被分配一部分槽给他,否则node4至关于没有工做,因此须要从新分片。以node3须要把槽15000~16384从新分配给node4为例:

  1. 开始对15000槽从新分配。
  2. node4准备导入属于15000槽的键值对。
  3. node3准备迁移属于15000槽的键值对。
  4. 若是node3存在15000槽的键值对,将这些键值对导入node4。
  5. 将槽指派给node4,完成对15000槽的从新指派。
  6. 其余槽的从新指派重复以上步骤。

当15555槽正在从node3转移到node4时,会出现一种状况就是15555槽对应的键值对有一部分在node3,另外一部分在node4。当客户端须要对15555槽下的一个键值对的更新时,node3会首先检查该键值对的key是否在当前节点,在就更新,不在返回ask错信信息,并指引客户端将该键值对写入node4。

复制和故障转移

在redis集群存在主从节点,主节点负责处理槽,从节点负责复制主节点以及当主节点下线时,替代下线的主节点继续处理槽。

复制

能够经过一下命令让接受该命令的节点成为node_id所指节点的从节点。

cluster replicate <node_id>
image-20201120203013924

执行该命令的流程:

  1. 接收到该命令的节点首先会在本身的clusterState.nodes字典中找到node_id所对应节点的clusterNode结构,并将本身的clusterState.myself.slaveof指针指向这个结构,以此来记录这个节点正在复制的主节点。
  2. 修改本身的clusterNode属性flags为REDIS_NODE_SLAVE和saveof属相指向主节点clusterNode1。
  3. 从节点调用复制代码,复制主节点。

一个节点的成为从节点,并开始复制主节点的信息会被告知其余全部全部节点,并去更新全部节点的clusterState中该主节点对应clusterNode结构的slaves和numslaves属性。

image-20201120204327179

故障转移

集群中的每一个节点互相ping其余节点,当没有收到有效回复,就会认定其节点下线。当集群中有一半的节点认定该节点下线,就会广播一条消息告知所有节点,将该节点认定为下线状态,并开始故障转移。

故障转移步骤:

  1. 在下线主节点的全部从节点里面选择一个从节点。
  2. 被选中的从节点会执行SLAVEOF no one命令,成为新的主节点。
  3. 新的主节点会撤销全部对已下线主节点的槽指派,并将这些槽所有指派给本身。
  4. 新的主节点向集群广播一条PONG消息,这条PONG消息可让集群中的其余节点当即知道这个节点已经由从节点变成了主节点,而且这个主节点已经接管了本来由已下线节点负责处理的槽。
  5. 新的主节点开始接收和本身负责处理的槽有关的命令请求,故障转移完成。

新的主节点选举基本和在redis的Sentinel模式中选举领头Sentinel基本类似,就不在多作详述能够翻开redis哨兵模式笔记。

参考:

redis设计与实现

相关文章
相关标签/搜索