Redis集群----槽指派底层原理

Redis集群通过分片的方式来保存数据库的键值对:集群的整个数据库被分为16384个槽,数据库中的每个键都输入这16384个槽其中的一个,集群中的每个节点都可以处理0-16384个槽。

当数据库中的16384个槽都有节点在处理时,集群处于上线状态;如果有任何一个槽没有得到处理,那么集群处于下线状态。

//通过向节点发送CLUSTER ADDSLOTS 命令,可以将一个或者多个槽指派给节点负责
CLUSTER ADDSLOTS <slot><slot...>

记录节点的槽指派信息

clausterNode结构的slouts属性和numslot属性记录了节点负责处理哪些槽:

struct clusterNode{
	//....
    unsigned char slots[16384/8];
    //该集群节点负责处理槽的数量 
    int numslots;
}

slots属性是一个二进制数组,数组长度为16384/8=2048位,包含16384个二进制位。

Redis以0位起始索引,16383为终止索引,对slots数组中的16384个二进制位进行编号,并根据索引i上的值来判断节点是否负责处理i:

    • 如果负责处理槽i,那么slots数组在索引i上的二进制的值为1
    • 如果不负责处理槽i,那么slots数组在索引i上的二进制的值为0

传播节点的槽指派信息

一个节点除了会将自己负责处理的槽记录在clusterNode结构的slots属性和numslots属性之外,它还会将自己的slots数组通过消息发送给集群中的其他节点,以此来告知其他节点自己目前负责哪些槽,其他节点会做出相应的改变。

例如:当节点A通过消息从节点B那里接收到节点B的slots数组时,节点A会在自己的clusterState.node字典中查到节点B对应的clusterNode结构,并对结构中的slots数组进行保存或者更新。

因为集群中的每个节点都会将自己的slots数组通过消息发送给集群中的其他节点,并且每个接收到slots数组的节点都会将数组的节点保存到相应节点的clusterNode结构里面,因此,集群中的每个节点都会知道数据库中的16384个槽分别指派给了集群中的哪些几点。

记录集群所有槽的指派信息

clusterState结构中的slots数组记录了集群中所有16384个槽的指派信息:

typedef struct clusterstate{
		
    clusterNode * slots[16384];
}

slots数组包含16384个项,每个数组项都都是一个指向clusterNode结构的指针:

  • 如果slots[i]指针指向null,那么表示槽i尚未指派给任何节点
  • 如果slots[i]指针指向一个clusterNode结构,那么表示槽i已经指派给了clusterNode结构所代表的节点。

如果只将槽指派信息保存在各节点的clusterNode.slots数组里,会出现一些无法搞笑解决的问题,而clusterState.slots数组的存在解决了这些问题

  • 如果节点只使用clusterNode.slots数组来记录槽的指派信息,那么为了知道槽i是否已经被指派,或者槽i被指派到了哪个节点,程序需要遍历ClusterState.Node里面的所有clusterNode结构,检查这些ClusterNode结构的slots数组,直到找到负责处理槽i的节点为止。
  • 而通过将所有槽的指派信息保存到clusterState.node数组里面,程序要检查槽i是否被指派,又或者取得负责处理i的节点,只需要范围clusterState.slots[i]的值即可,操作复杂的仅为O(1)

虽然clusterState.slots数组记录了集群中所有槽的指派信息,但是使用clusterNode结构的slots数组来记录单个节点的槽指派信息仍然是有必要的:

  • 如果不使用clusterNode.slots数组,而单独使用clusterState.slots数组的话,每次要将某个节点A的槽指派信息传播给其他节点时,程序必须要先遍历整个clusterState.slots数组,记录节点A负责处理哪些槽,然后才能发送节点A的槽指派信息,这比直接发送clusterNode.slots数组要低效和麻烦的多。

总结:clusterState.slots数组记录了集群中所有槽的指派信息,而clusterNode.slots数组只记录了clusterNode结构所代表的节点槽指派信息。

CLUSTER ADDSLOTS 命令的实现

CLUSTER ADDSLOTS 命令接收一个或多个槽作为参数,并将所有输入的槽指派给接收该命令的节点负责


CLUSTER ADDSLOTS <SLOT>[slot ........]

CLUSTER ADDSLOTS命令的基本逻辑

  • 首先遍历搜索的输入槽,检查它们是否都是未指派槽,如果有一个槽被指派了某个节点,就终止命令并返回错误信息
  • 如果都是未指派槽,那么再次遍历所有输入槽,将这些槽指派给当前节点
    • 将clusterState.slots[i]的指针指向当前节点的clusterNode结构
    • 将数组在索引i上的二进制位都设置为 1
clusterState[i] = clusterState.myself
setSlotBit(clusterState.myself.slots,i);

最后,在CLUSTER ADDSLOTS 命令执行完毕之后,节点会通过发送消息告知集群中的其他节点,自己目前在处理哪些槽

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值