bigywater.tech
Redis · 71

Redis Cluster 客户端重定向

集群客户端要么自己路由,要么每次都被服务器「指路」。指路要多花一次往返。这篇把三种常见策略在同一个集群上对比:完全不缓存槽位表、只在收到 MOVED 时记一个槽、启动时拉整张槽位表;然后在线迁移 1000 个槽,看手里是旧表的客户端要被指多少次路,才能恢复。

67%
无槽位表的客户端 MOVED 占比(随机 key,3 个主库,期望 2/3)
47.7 → 28.8 µs
平均每个 GET 的耗时:不缓存 → 拉全表(本机回环)
789 vs 1
迁移 1000 个槽后:只更新一个槽 vs 整表刷新 的 MOVED 次数

三种策略,稳定的集群

30000 次 GET,key 随机
实测 · 本机执行输出
策略                                   请求数   MOVED     每请求往返数     平均耗时 µs
没有槽位表,只会跟 MOVED,不学习                30000   19987       1.67        47.7
没有槽位表,每次 MOVED 学一个槽                30000    9507       1.32        37.9
启动时 CLUSTER SLOTS 拉全表              30000       0       1.00        28.8

「无表、不学习」的客户端固定连第一个节点,遇到 MOVED 就换节点重发,但下次仍从原点出发:19987 次 MOVED,约 2/3(3 个主库里只有 1/3 的 key 恰好在这个节点上),每个请求平均 1.67 次往返。「每次 MOVED 学一个槽」把指过的路记下来,MOVED 降到 9507 次,但 30000 个 key 散在很多槽上,仍然要被指很多次。「启动时拉全表」用 CLUSTER SLOTS 一次拿到整张槽位表,之后 MOVED 为 0,每个请求恰好一次往返,平均耗时最低(28.8 µs)。本机回环上,每多一次往返约多 28 µs;跨机器网络时代价更大。

在线迁移 1000 个槽

实测 · 本机执行输出
reshard 耗时 1.0 s;槽 0–999 中现在属于第二个主库的:1000 个

redis-cli --cluster reshard --cluster-from A --cluster-to B --cluster-slots 1000 用 1.0 s 把槽 0–999 从第一个主库搬到第二个,期间集群一直可用(这里每个槽里的 key 很少)。迁移结束后有两个客户端手里还是迁移之前拉的槽位表。

旧槽位表怎么恢复

各读 20000 次落在这 1000 个槽里的 key
实测 · 本机执行输出
策略                                     请求数   MOVED     每请求往返数     平均耗时 µs
旧表 + 每次 MOVED 只更新那一个槽              20000     789       1.04        29.7
旧表 + 第一次 MOVED 就重新拉全表              20000       1       1.00        28.9
(2000 个 key 覆盖了 789 个不同的槽)

只更新被指路的那一个槽:20000 次读里有 789 次 MOVED——2000 个 key 覆盖了 789 个不同的槽,每个槽被纠正一次,1.04 次往返/请求。收到第一次 MOVED 就重新拉整张表:只有 1 次 MOVED,之后全部命中。MOVED 说明「地图变了」,而不仅仅是「这一个槽变了」——一次迁移常常一次搬很多槽,整表刷新更划算。(代价是刷新时多一次 CLUSTER SLOTS 调用;槽位变化频繁时要防止「MOVED 风暴」引起的反复刷新,我没有测这个场景。)

分步演示:三种策略与一次迁移

Redis Cluster 客户端重定向
本步的数据

    本文用到的工具与边界

    • 本机 macOS 27 / Redis 8.10.2 独立实例(本机回环端口,save 关闭),redis-cli 风格输出由自写的 RESP 客户端打印;计时用 time.perf_counter,数字每次运行会有小幅抖动。客户端是我手写的:三种策略各由构造参数控制;3 主 3 从,单连接同步请求,每次 GET 的耗时含一次往返
    • 没有验证:ASK 期间客户端的行为(第 70 篇覆盖了协议本身)、多线程客户端刷新槽位表的并发问题、真实库(如 redis-py-cluster、Lettuce、Jedis)的具体策略、跨机器网络下的耗时
    京ICP备2026067502号-1京公网安备11010502063487号