Redis(设计与实现):54---集群之计算键所属槽(CLUSTER KEYLOST命令)、判断槽所属节点、MOVED错误

一、计算键所属槽(CLUSTER KEYLOST命令)

使用的算法(CRC16语句)

  • 节点使用以下伪代码算法来计算给定键key属于哪个槽:
def slot_number(key):
    return CRC16(key) & 16383
  • 其中CRC16(key)语句用于计算键key的CRC-16校验和,而&16383语句则用于计算出 一个介于0至16383之间的整数作为键key的槽号

CLUSTER KEYLOST命令

  • 使用“CLUSTER KEYSLOT <key>命令”可以查看一个给定键属于哪个槽:
  • 例如:

  • CLUSTER KEYSLOT命令就是通过调用上面给出的槽分配算法来实现的,以下是该命令 的伪代码实现:
def CLUSTER_KEYSLOT(key):
    # 计算槽号
    slot = slot_number(key)
    # 将槽号返回给客户端
    reply_client(slot)

二、判断槽所属节点(struct clusterState.slots数组)

  • 当节点计算出键所属的槽i之后,节点就会检查自己在clusterState.slots数组中的项i,判断键所在的槽是否由自己负责:
    • 如果clusterState.slots[i]等于clusterState.myself,那么说明槽i由当前节点负责,节点可以执行客户端发送的命令
    • 如果clusterState.slots[i]不等于clusterState.my self,那么说明槽i并非由当前节点负责,节点会根据clusterState.slots[i]指向的clusterNode结构所记录的节点IP和端口号,向客户端返回MOVED错误,指引客户端转向至正在处理槽i的节点

演示案例

  • 举个例子,假设下图为节点7000的clusterState结构:
    • 当客户端向节点7000发送命令SET date"2013-12-31"的时候,节点首先计算出键date属于槽2022,然后检查得出clusterState.slots[2022]等于clusterState.myself,这说明槽2022正是由节点7000负责,于是节点7000直接执行这个SET命令,并将结果返回给发送命令的客户端
    • 当客户端向节点7000发送命令SET msg"happy new year!"的时候,节点首先计算出键 msg属于槽6257,然后检查clusterState.slots[6257]是否等于clusterState.my self,结果发现两者并不相等:这说明槽6257并非由节点7000负责处理,于是节点7000访问 clusterState.slots[6257]所指向的clusterNode结构,并根据结构中记录的IP地址127.0.0.1和端口号7001,向客户端返回错误MOVED 62  127.0.0.1:7001,指引节点转向至正在负责处理槽6257的节点7001

三、MOVED错误

  • 何时出现?当节点发现键所在的槽并非由自己负责处理的时候,节点就会向客户端返回一个 MOVED错误,指引客户端转向至正在负责槽的节点
  • MOVED错误的格式为:
    • 其中slot为键所在的槽,而ip和port则是负责处理槽slot的节点的IP地址和端口号
MOVED <slot> <ip>:<port>
  • 当客户端接收到节点返回的MOVED错误时,客户端会根据MOVED错误中提供的IP地址和端口号,转向至负责处理槽slot的节点,并向该节点重新发送之前想要执行的命令
  • 一个集群客户端通常会与集群中的多个节点创建套接字连接,而所谓的节点转向实际上就是换一个套接字来发送命令
  • 如果客户端尚未与想要转向的节点创建套接字连接,那么客户端会先根据MOVED错误提供的IP地址和端口号来连接节点,然后再进行转向

单机模式/集群模式下MOVED错误的显示

  • 集群模式的redis-cli客户端在接收到MOVED错误时,并不会打印出MOVED错误, 而是根据MOVED错误自动进行节点转向,并打印出转向信息,所以我们是看不见节点返回的MOVED错误的:

  • 但是,如果我们使用单机(stand alone)模式的redis-cli客户端,再次向节点7000发送相同的命令,那么MOVED错误就会被客户端打印出来:

  • 这是因为单机模式的redis-cli客户端不清楚MOVED错误的作用,所以它只会直接将 MOVED错误直接打印出来,而不会进行自动转向

演示案例

  • 以前 面的客户端从节点7000转向至7001的情况作为例子:

  • 下图展示了客户端向节点7000发送SET命令,并获得MOVED错误的过程

  • 而下图则展示了客户端根据MOVED错误,转向至节点7001,并重新发送SET命令的 过程

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

董哥的黑板报

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值