Redis Cluster 数据分片

介绍 Redis ClusterRedis 集群是 Redis 提供的分布式数据库方案, 集群通过分片(sharding) 来进行数据共享,并提供复制和故障转移功能 。
节点一个 Redis 集群通常由多个节点(node) 组成,在刚开始的时候,每个节点都是相互独立的 , 它们都处于一个只包含自己的集群当中,要组建一个真正可工作的集群,我们必须将各个独立的节点连接起来,构成一个包含多个节点的集群 。
连接各个节点的工作可以使用 cluster meet 命令来完成,该命令的格式如下:cluster meet < ip >< port > 。节点通过握手来将其他节点添加到自己所处的集群当中 。向一个 node 节点发送 cluster meet 命令, 可以让 node 节点与 ip 和 port 所指定的节点进行握手(handshake) , 当握手成功时,node 节点就会将 ip 和 port 所指定的节点添加到 node 节点当前所在的集群中 。
一个节点就是一个运行在集群模式下的 Redis 服务器,Redis 服务器在启动时会根据 cluster-enabled 配置选项是否为 yes 来决定是否开启服务器的集群模式 。启动服务器时,服务器判断是否开启集群模式:

  • 如果 cluster-enabled 选项的值为 yes , 则开启服务器的集群模式 , 成为一个节点;
  • 如果 cluster-enabled 选项的值不为 yes,则开启服务器的单机(stand alone)模式,成为一个普通的 Redis 服务器 。
节点会继续使用 redisServer 结构来保存服务器的状态, 使用 redisClient 结构来保存客户端的状态,至于那些只有在集群模式下才会用到的数据,节点将它们保存到了cluster.h/clusterNode 结构、 cluster.h/clusterLink 结构 , 以及 cluster.h/clusterState 结构里面 。
槽指派Redis 集群通过分片的方式来保存数据库中的键值对:集群的整个数据库被分为 16384 个槽(slot),数据库中的每个键都属于这 16384 个槽的其中一个,集群中的每个节点可以处理 0 个或最多 16384 个槽 。
通过向节点发送 cluster addslots 命令,我们可以将一个或多个槽指派(assign)给节点负责:cluster addslots < slot > [slot ...] 。
在 cluster addslots 命令执行完毕之后,节点会通过发送消息告知集群中的其他节点,自己目前正在负责处理哪些槽 。也就是说,每个节点都会记录哪些槽指派给了自己 , 而哪些槽又被指派给了其他节点 。
集群的在线状态:
  • 上线状态:当数据库中的 16384 个槽都有节点在处理时,集群处于上线状态(ok);
  • 下线状态:相反地,如果数据库中有任何一个槽没有得到处理,那么集群处于下线状态(fail) 。
节点保存槽指派信息Redis 集群的每个节点都会记录自己负责处理哪些槽 。
clusterNode 结构的 slots 属性和 numslot 属性记录了节点负责处理哪些槽:
struct clusterNode {// ...unsigned char slots[16384/8];int numslots;// ...};slots 属性是一个二进制位数组,这个数组的长度为 16384 / 8 = 2048 个字节,共包含 16384 个二进制位 。Redis 以 0 为起始索引,16383 为终止索引 , 对 slots 数组中的 16384 个二进制位进行编号,并根据索引 i 上的二进制位的值来判断节点是否负责处理槽 i:
  • 如果 slots 数组在索引 i 上的二进制位的值为 1,那么表示节点负责处理槽 i 。
  • 如果 slots 数组在索引 i 上的二进制位的值为 0,那么表示节点不负责处理槽 i 。
numslots 属性则记录节点负责处理的槽的数量,也即是 slots 数组中值为 1 的二进制位的数量 。
节点之间传播槽指派信息一个节点除了会将自己负责处理的槽记录在 clusterNode 结构的 slots 属性和 numslots 属性之外,它还会将自己的 slots 数组通过消息发送给集群中的其他节点,以此来告知其他节点自己目前负责处理哪些槽 。
当节点 A 通过消息从节点 B 那里接收到节点 B 的 slots 数组时 ,  节点 A 会在自己的 clusterState.nodes 字典中查找节点 B 对应的 clusterNode 结构 , 并对结构中的 slots 数组进行保存或者更新 。
因为集群中的每个节点都会将自己的 slots 数组通过消息发送给集群中的其他节点,并且每个接收到 slots 数组的节点都会将数组保存到相应节点的 clusterNode 结构里面 ,  因此, 集群中的每个节点都会知道数据库中的 16384 个槽分别被指派给了集群中的哪些节点 。
记录集群所有槽的指派信息Redis 集群的每个节点都会记录集群所有槽的指派信息
clusterState 结构中的 slots 数组记录了集群中所有 16384 个槽的指派信息:
typedef struct clusterState {// ...clusterNode *slots[16384];// ...} clusterState;

推荐阅读