1. 引言
上一篇文章中,我们介绍了 redis 集群的搭建。 redis 集群详解及搭建过程 其中我们遇到了报错:
这就是所谓的“MOVED转向”,那么什么是 MOVED 转向呢?本篇日志我们就来介绍一下。
2. MOVED 转向
当我们使用操作 redis 单节点的 client 来操作集群时,常常能够遇到上面的报错。 按照 redis 官方规范,一个 Redis 客户端可以向集群中的任意节点(包括从节点)发送命令请求。 节点会对命令请求进行分析,如果该命令是集群可以执行的命令,那么节点会查找这个命令所要处理的键所在的槽。 如果处理该命令的槽位于当前节点,那么命令可以顺利执行,否则当前节点会返回 MOVED 错误,让客户端到另一个节点执行该命令。 redis 官方规范要求所有客户端都应处理 MOVED 错误,从而实现对用户的透明。 我们上面看到的错误就是 MOVED 错误:
代码语言:javascript复制(error) MOVED 866 172.21.16.4:6379
他表示,该执行该命令所需要的 slot 是 866 号哈希槽,负责该槽的节点是 172.21.16.4:6379。
2.1. 性能优化
每次 REDIS 指令操作后,客户端应该记录下正确的节点与槽之间的对应关系 — 槽位路由表。 这样在下次指令执行时可以找到正确的节点,从而提升效率。
2.2. Redis 的哲学
Redis 的规范体现出了 Redis 的哲学 — 保持 server 端的尽量简洁,能不在 server 端做的事情都不在 server 端做。 这已经是我们不止一次提到的原则了。
3. 槽位的迁移
ASK 转向是在集群在线重配置发生时出现的一种错误返回。 所谓的集群在线重配置就是 slot 的迁移,下面是用于 slot 迁移的命令:
- CLUSTER ADDSLOTS slot1 [slot2] … [slotN] — 指派槽位到节点
- CLUSTER DELSLOTS slot1 [slot2] … [slotN] — 从节点移除槽位
- CLUSTER SETSLOT slot NODE node — 设置槽位到某节点
- CLUSTER SETSLOT slot MIGRATING node — 将槽 slot 迁移出当前节点,移入 node 节点
- CLUSTER SETSLOT slot IMPORTING node — 接受从 node 节点迁移出的槽位 slot
前面的命令很好理解,只有最后的两条命令需要详细解释: 假设我们在 A 节点执行:
代码语言:javascript复制CLUSTER SETSLOT 866 MIGRATING B
同时,我们在 B 节点执行:
代码语言:javascript复制CLUSTER SETSLOT 866 IMPORTING A
这样,我们将 866 号槽从 A 节点迁移到 B 节点。 这样,再次请求 866 槽时,都会判断操作的键是否是一个新的键,如果是一个新的键,那么就在 B 节点中进行操作,否则仍然在 A 节点中进行操作。 对于试图在 A 节点中 866 槽上新增键的操作,A 节点会返回一个 ASK 转向错误,指向 B 节点。 也就是说,MIGRATING、IMPORTING 命令不会进行数据的迁移,只决定新数据的去向。 而在这一组操作进行中,这两个节点都会被阻塞,以免竞争条件的发生。
4. ASK 转向
除了 MOVED 转向,Redis 规范还要求客户端实现对 ASK 转向的处理。 MOVED 转向与 ASK 转向的区别类似于 http 协议中 301 跳转与 302 跳转的区别:
- MOVED 转向 — 当节点需要让一个客户端长期地(permanently)将针对某个槽的命令请求发送至另一个节点时,节点向客户端返回 MOVED 转向
- ASK 转向 — 当节点需要让客户端仅仅在下一个命令请求中转向至另一个节点时,节点向客户端返回 ASK 转向
客户端是不能直接请求 ASK 转向的目标机器的,而是必须先发送一个 ASKING 命令。 因此,客户端也没有必要了解或保存槽位与节点的对应关系。
5. 参考资料
https://redis.io/topics/cluster-spec。 https://redis.io/commands/cluster-setslot。 https://github.com/go-redis/redis/blob/master/cluster.go。