写点什么

Redis 集群架构剖析 (3):集群处理 redis-cli 指令

作者:非晓为骁
  • 2022 年 3 月 21 日
  • 本文字数:1690 字

    阅读完需:约 6 分钟

在前两篇 Redis 集群架构剖析中,我们创建了一个集群,并且把这个集群由下线状态启动为上线状态。集群上线之后,就表示我们可以向集群的节点发送数据命令了。在开始之前,依旧可以先思考下面的问题:


  • 节点如何找到要处理的数据(这个其实在上一篇有提到)?

  • 如果不是该节点处理的数据,节点会怎么做?




  针对上面的问题,结合前两篇的内容,大致可以猜一下流程可以是,先找到对应的 key 的槽位在哪?是不是我发送到的节点上面处理的,如果是的话就执行,不是的话可能就转给负责这个槽位的节点。无论是读和写,都需要找到槽位对应的节点。下面具体介绍一下的集群处理指令时的操作

大体流程



  从上图可以看到和我们预想的差不多:


  1. redis-cli 向节点发送数据库命令

  2. 收到命令的节点计算建属于哪个槽,然后判断是否在本节点

  3. 如果在本节点,则执行命令

  4. 如果不在本节点,会返回一个MOVED错误给 redis-cli,然后客户端会根据MOVED提供的信息转向正确的节点


  举个例子,6370 要执行两个指令(槽位我是乱写的):


127.0.0.1:6370 > GET i"200" #在当前节点直接执行
127.0.0.1:6370 > SET new 100-> Redirected to slot [15045] located at 127.0.0.1:6371OK
127.0.0.1:6371 > GET new100
复制代码


  这里面的三个重点:


  • 节点如何计算键对应的槽位

  • 节点如何找到槽位对应的节点

  • MOVED错误是什么?包含什么消息?执行了什么?

key 属于哪个槽

  节点使用下面这个算法来计算键对应的槽位:


def slot_number(key):  return CRC16(key) & 16383
复制代码


  CRC16(key)语句用与计算 key 的 CRC-16 校验和,而 &16383 适用于算出一个介于 0 ~ 16383 之间的证书作为 key 的槽位:


127.0.0.1:6370 > CLUSTER KEYSLOT "Im"(integer) 2655
127.0.0.1:6370 > CLUSTER KEYSLOT "best"(integer) 10040
复制代码


  KEYSLOT的伪代码如下


def CLUSTER_KEYSLOT(key):  // 计算槽位  slot = slot_number(key)         // 将槽位返回给客户端    reply_client(slot)
复制代码

slot 属于哪个节点

  当节点计算出 key 多数的 slot 之后,节点就会检查自己的clusterState.slots数组中的 index i,判断 key 所在的 slot 是否由自己负责:


  • 如果clusterState.slots[i]等于 clusterState.myself,就表示 slot i 由当前节点负责,节点可以直接执行客户端发送的命令

  • 如果不是,而是其他的clusterNode,节点会根据指向的clusterNode结构所记录的节点的 IP 和 PORT,向客户端发送MOVED错误,指引客户端转向至正确处理该 slot 的节点。


  如下图,slot 2655 指向的就是 myself 节点,当前节点直接执行即可。slot 15045 是另外的节点,所以需要返回给客户端MOVED错误。



MOVED错误

  当节点发现键所在槽并非由自己负责处理的时候,节点就会向客户端返回一个MOVED错误,指引客户端转向至正在负责该 slot 的节点。


  下面为MOVED的格式


# <slot> : key所在slot# <ip>:<port> 负责处理slot的节点的IP和PORTMOVED <slot> <ip>:<port>
MOVED 15045 127.0.0.1:6371
复制代码


  当客户端接收到节点返回的MOVED的错误时,客户端会根据MOVED错误中的 IP 和 PORT,转向至负责处理改 slot 的节点,并向该节点重新发送之前想要执行的命令。


  以上面 redirect 的例子为例:


127.0.0.1:6370 > SET new 100-> Redirected to slot [15045] located at 127.0.0.1:6371OK
复制代码



  一个集群客户端通常与集群终端额多个几点创建套接字连接,而所谓的节点转向实际上就是换一个套接字来发送命令。


  MOVED错误一般在集群模式下会被隐藏,而是向上面的例子,直接转向到对应的节点。如果想要查看这个错误的话,需要使用单机模式进入,也就是 redis-cli 的时候不要带-c,那么以上面的例子来说就会返回


(error) MOVED 15045 127.0.0.1:6371
复制代码


  注意,单机和集群模式下的数据库方面有一个区别是,集群节点只能使用 0 号数据库,而不是向单机那样 0-15




  这篇文档,我们了解了集群是如何处理由客户端发过来的指令的,再结合一下前两篇的数据结构,就会很容易理解。这篇文档的场景是普遍场景,就好比写代码时自己测试一点问题都没有,但是如果节点发生槽转移呢,或者重新分配槽呢?针对这个一个异常行为,我们下节分析。




系列文章:

  1. Redis 集群架构剖析 (1):认识 cluster

  2. Redis 集群架构剖析 (2):槽位

用户头像

非晓为骁

关注

no pain no gain 2019.04.10 加入

用我的勤奋,一点一点地努力,提升自己的能力,拓展自己的视野,提高自己的认知。 我的知乎:https://www.zhihu.com/people/zhengfke

评论

发布
暂无评论
Redis集群架构剖析(3):集群处理redis-cli指令_redis_非晓为骁_InfoQ写作平台