Redis Cluster 数据分片( 四 )

  • redis-trib 向源节点发送 cluster getkeysinslot < slot > < count > 命令,获得最多 count 个属于槽 slot 的键值对的键名(key name) 。
  • 对于步骤 3 获得的每个键名,redis-trib 都向源节点发送一个 migrate <target_ip> <target_port> <key_name> 0 < timeout > 命令,将被选中的键原子地从源节点迁移至目标节点 。
  • 将属于槽 slot 的键全部迁移至目标节点:重复执行步骤 3 和步骤 4,直到源节点保存的所有属于槽 slot 的键值对都被迁移至目标节点为止 。
  • 将槽 slot 指派给目标节点:redis-trib 向集群中的任意一个节点发送 cluster setslot < slot > node <target_id> 命令,将槽 slot 指派给目标节点,这一指派信息会通过消息发送至整个集群,最终集群中的所有节点都会知道槽 slot 已经指派给了目标节点 。
  • 如果重新分片涉及多个槽,那么 redis-trib 将对每个给定的槽分别执行上面给出的步骤 。

  • Redis Cluster 数据分片

    文章插图
    ask 错误在进行重新分片期间,源节点向目标节点迁移一个槽的过程中,可能会出现这样一种情况:属于被迁移槽的一部分键值对保存在源节点里面,而另一部分键值对则保存在目标节点里面 。
    当客户端向源节点发送一个与数据库键有关的命令,并且命令要处理的数据库键恰好就属于正在被迁移的槽时:
    • 源节点会先在自己的数据库里面查找指定的键,如果找到的话,就直接执行客户端发送的命令 。
    • 相反地,如果源节点没能在自己的数据库里面找到指定的键,那么这个键有可能已经被迁移到了目标节点,源节点将向客户端返回一个 ask 错误,指引客户端转向正在导入槽的目标节点,并再次发送之前想要执行的命令 。
    如果节点 A 正在迁移槽 i 至节点 B,那么当节点 A 没能在自己的数据库中找到命令指定的数据库键时,节点 A 会向客户端返回一个 ask 错误,指引客户端到节点 B 继续查找指定的数据库键 。
    源节点判断是否需要向客户端发送 ask 错误的整个过程 。
    Redis Cluster 数据分片

    文章插图
    被隐藏的 ask 错误:和接到 moved 错误时的情况类似,集群模式的 redis-cli 在接到 ask 错误时也不会打印错误,而是自动根据 ask 错误提供的 IP 地址和端口进行转向动作 。
    ask 错误如果节点收到一个关于键 key 的命令请求,并且键 key 所属的槽 i 正好就指派给了这个节点,那么节点会尝试在自己的数据库里查找键 key:
    • 如果找到了的话,节点就直接执行客户端发送的命令 。
    • 与此相反,如果节点没有在自己的数据库里找到键 key,那么节点会检查自己的 clusterState.migrating_slots_to[i],看键 key 所属的槽 i 是否正在进行迁移,如果槽 i 的确在进行迁移的话,那么节点会向客户端发送一个 ask 错误,引导客户端到正在导入槽 i 的节点去查找键 key 。
    接到 ask 错误的客户端会根据错误提供的 IP 地址和端口号,转向至正在导入槽的目标节点,然后首先向目标节点发送一个 asking 命令,之后再重新发送原本想要执行的命令 。
    asking 错误当客户端接收到 ask 错误并转向至正在导入槽的节点时,客户端会先向节点发送一个 asking 命令,然后才重新发送想要执行的命令,这是因为如果客户端不发送 asking 命令,而直接发送想要执行的命令的话,那么客户端发送的命令将被节点拒绝执行,并返回 moved 错误 。
    asking 命令唯一要做的就是打开发送该命令的客户端对应的实例结构的 REDIS_ASKING 标识,以下是该命令的伪代码实现:

    经验总结扩展阅读