经过前几章,咱们已经了解redis从单机版、高并发的主从架构和保证高可用的哨兵模式。可是主从架构的高并发是针对那些读远大于写的场景,若是要保证读和写都是高并发的场景呢?那就是能够使用redis集群模式。html
redis集群模式一般是有多个redis节点组成。Redis服务器在启动时会根据cluster-enabled配置选项是否为yes来决定是否开启服务器的集群模式。node
# cluster-enabled yes cluster-enabled yes
当启动集群模式后,在集群中的每一个节点都会存在一个clusterState数据结构。这个结构记录了在当前节点的视角下,集群目前所处的状态,例如集群是在线仍是下线,集群包含多少个节点,集群当前的配置纪元等信息。以下图为node1的clusterState结构。web
在一个三个redis节点组成的redis集群中,当咱们往该集群写入一个命令,那这个命令会被写入到哪一个节点呢?redis
redis集群将整个数据库分为16384个槽(slot)。每一个redis节点负责其中一部分的槽,当16384个槽都有redis节点负责时,整个redis集群才能正常工做。算法
为啥是16384个槽(slot)数据库
参考博文数组
因此往redis集群写入一个命令后,当前节点经过CRC16(key)和&12384计算出一个位于1~16384之间的值,该值决定这对键值对属于哪一个槽。bash
在redis每个节点中都保存在这个一个关于redis集群的clusterState结构,这个结构包含这个当前这个集群的相关信息,其中也包含着全部槽的指派信息。服务器
如上图所示,在一个三个redis节点的集群中,每个redis节点都存在这clusterState信息。ClusterState结构中有slots属性,并指向一个大小为16384的redisNode数组。网络
命令写入的流程:
在起初全部槽没有被指派时,能够经过执行如下命令将一个或者多个槽指派当前执行该命令的redis节点。
# CLUSTER MEET <slot> [slot...]
CLUSTER MEET 0,1,2,3
槽信息会被保存在redisnode节点结构的slots和numslot属性中,其中slots是一个二进制数组大小为16383,该数组的索引正好对应16384个槽,值为0或1,1就表示该索引对应槽由当前redis节点负责;numslot记录当前redis节点负责的槽总数。
在一个集群的中redis节点会相互网络链接发送信息,并告知对方本身在负责哪些槽。其余redis节点收到信息后,会更新本身的clusterState结构信息,主要是包含所有槽信息的clusterState.slots属性和clusterState.nodes中对应节点的clusterNode.slots和numslot信息。所以每个redis节点中都保存在完整的槽节点指派信息。
在三个节点的redis集群,当要给该集群在增长一个节点node4时,槽在已被所有分配,可是node4须要被分配一部分槽给他,否则node4至关于没有工做,因此须要从新分片。以node3须要把槽15000~16384从新分配给node4为例:
当15555槽正在从node3转移到node4时,会出现一种状况就是15555槽对应的键值对有一部分在node3,另外一部分在node4。当客户端须要对15555槽下的一个键值对的更新时,node3会首先检查该键值对的key是否在当前节点,在就更新,不在返回ask错信信息,并指引客户端将该键值对写入node4。
在redis集群存在主从节点,主节点负责处理槽,从节点负责复制主节点以及当主节点下线时,替代下线的主节点继续处理槽。
能够经过一下命令让接受该命令的节点成为node_id所指节点的从节点。
cluster replicate <node_id>
执行该命令的流程:
一个节点的成为从节点,并开始复制主节点的信息会被告知其余全部全部节点,并去更新全部节点的clusterState中该主节点对应clusterNode结构的slaves和numslaves属性。
集群中的每一个节点互相ping其余节点,当没有收到有效回复,就会认定其节点下线。当集群中有一半的节点认定该节点下线,就会广播一条消息告知所有节点,将该节点认定为下线状态,并开始故障转移。
故障转移步骤:
新的主节点选举基本和在redis的Sentinel模式中选举领头Sentinel基本类似,就不在多作详述能够翻开redis哨兵模式笔记。
参考:
redis设计与实现