Redis Cluster 数据分片( 三 )

3、moved 错误的实现方法当节点发现键所在的槽并非由自己负责处理的时候,节点就会向客户端返回一个 moved 错误,指引客户端转向至负责处理槽的节点 。
moved 错误的格式为:moved < slot > < ip > : < port > 。其中 slot 为键所在的槽,而 ip 和 port 则是负责处理槽 slot 的节点的 IP 地址和端口号 。
当客户端接收到节点返回的 moved 错误时,客户端会根据 moved 错误中提供的 IP 地址和端口号,转向至负责处理槽 slot 的节点,并向该节点重新发送之前想要执行的命令 。
一个集群客户端通常会与集群中的多个节点创建套接字连接,而所谓的节点转向实际上就是换一个套接字来发送命令 。如果客户端尚未与想要转向的节点创建套接字连接,那么客户端会先根据 moved 错误提供的 IP 地址和端口号来连接节点,然后再进行转向 。
被隐藏的 moved 错误:集群模式的 redis-cli 客户端在接收到 moved 错误时,并不会打印出 moved 错误,而是根据 moved 错误自动进行节点转向,并打印出转向信息,所以我们是看不见节点返回的 moved 错误的 。但是,如果我们使用单机(stand alone)模式的 redis-cli 客户端,moved 错误就会被客户端打印出来 。这是因为单机模式的 redis-cli 客户端不清楚 moved 错误的作用,所以它只会直接将 moved 错误直接打印出来,而不会进行自动转向 。
节点数据库的实现集群节点保存键值对以及键值对过期时间的方式,与单机 Redis 服务器保存键值对以及键值对过期时间的方式完全相同 。节点和单机服务器在数据库方面的一个区别是,节点只能使用 0 号数据库,而单机 Redis 服务器则没有这一限制 。
除了将键值对保存在数据库里面之外,节点还会用 clusterState 结构中的 slots_to_keys 跳跃表来保存槽和键之间的关系:
typedef struct clusterState {// ...zskiplist *slots_to_keys;// ...} clusterState;slots_to_keys 跳跃表每个节点的分值(score)都是一个槽号,而每个节点的成员(member)都是一个数据库键:

  • 每当节点往数据库中添加一个新的键值对时,节点就会将这个键以及键的槽号关联到 slots_to_keys 跳跃表 。
  • 当节点删除数据库中的某个键值对时,节点就会在 slots_to_keys 跳跃表解除被删除键与槽号的关联 。
通过在 slots_to_keys 跳跃表中记录各个数据库键所属的槽,节点可以很方便地对属于某个或某些槽的所有数据库键进行批量操作,例如命令 cluster getkeysinslots < slot > < count > 命令可以返回最多 count 个属于槽 slot 的数据库键,而这个命令就是通过遍历 slots_to_keys 跳跃表来实现的 。
重新分片介绍重新分片Redis 集群的重新分片操作可以将任意数量已经指派给某个节点 (源节点)的槽改为指派给另一个节点(目标节点),并且相关槽所属的键值对也会从源节点被移动到目标节点 。
重新分片操作可以在线(online)进行,在重新分片的过程中,集群不需要下线,并且源节点和目标节点都可以继续处理命令请求 。
重新分片的实现原理Redis 集群的重新分片操作是由 Redis 的集群管理软件 redis-trib 负责执行的,Redis 提供了进行重新分片所需的所有命令,而 redis-trib 则通过向源节点和目标节点发送命令来进行重新分片操作 。
redis-trib 对集群的单个槽 slot 进行重新分片的步骤如下:
  1. 目标节点准备导入槽 slot 的键值对:redis-trib 对目标节点发送 cluster setslot < slot > importing <source_id> 命令,让目标节点准备好从源节点导入(import)属于槽 slot 的键值对 。
  2. 源节点准备迁移槽 slot 的键值对:redis-trib 对源节点发送 cluster setslot < slot > migrating <target_id> 命令,让源节点准备好将属于槽 slot 的键值对迁移(migrate)至目标节点 。

    经验总结扩展阅读