Redis Cluster 不按节点分数据,而是先把整个键空间切成 16384 个槽,再把槽分给主库。所有关于「数据在哪」的问题,都是在问「这个槽在哪个节点上」。这篇从零搭一个 3 主 3 从的集群,看槽位怎么分配、怎么查询,并把 10 万个 key 写进去,量它们在槽和节点上的实际分布。
Master[0] -> Slots 0 - 5460 Master[1] -> Slots 5461 - 10922 Master[2] -> Slots 10923 - 16383 Adding replica 127.0.0.1:7304 to 127.0.0.1:7300 Adding replica 127.0.0.1:7305 to 127.0.0.1:7301 Adding replica 127.0.0.1:7303 to 127.0.0.1:7302 [OK] All 16384 slots covered.
redis-cli --cluster create 把 16384 个槽按顺序平均切成三段:0–5460、5461–10922、10923–16383(5461 + 5462 + 5461)。三个从库随机挂到三个主库下。(为了让从库快点同步,实验中的每个节点都设了 repl-diskless-sync-delay 0,默认是 5 秒。)
b17c901b 127.0.0.1:7300 myself,master 主=- epoch=1 槽=0-5460 3625acd4 127.0.0.1:7301 master 主=- epoch=2 槽=5461-10922 3b88246a 127.0.0.1:7302 master 主=- epoch=3 槽=10923-16383 b9107523 127.0.0.1:7303 slave 主=3625acd4 epoch=2 槽=- 24408076 127.0.0.1:7304 slave 主=3b88246a epoch=3 槽=- e1ff2e34 127.0.0.1:7305 slave 主=b17c901b epoch=1 槽=-
每个主库有各自的 epoch(1、2、3),槽位区间写在每个主库那一行;从库那一行的第四列是它主库的 ID。同一个集群里所有节点看到的这张表是一致的,--cluster check 的 All nodes agree about slots configuration 检查的就是这一点。
客户端总重定向次数:MOVED 0(客户端从一开始就有完整槽位表)
各主库 DBSIZE: {7300: 33359, 7301: 33289, 7302: 33352} 合计 100000我的客户端用自己实现的 CRC16 先算出每个 key 的槽位,再发给对应的主库,10 万次写入 MOVED 为 0。三个主库的 DBSIZE 是 33359、33289、33352,合计 100000,几乎均分。这里的 key 是 user:0 到 user:99999,没有使用 hash tag(第 72 篇)。
CLUSTER SLOTS 槽 0–5460 共 5461 个 主 127.0.0.1:7300 从 [7305] CLUSTER SLOTS 槽 5461–10922 共 5462 个 主 127.0.0.1:7301 从 [7303] CLUSTER SLOTS 槽 10923–16383 共 5461 个 主 127.0.0.1:7302 从 [7304] CLUSTER SHARDS 槽 0–5460:master@7300(online) replica@7305(online) CLUSTER SHARDS 槽 5461–10922:master@7301(online) replica@7303(online) CLUSTER SHARDS 槽 10923–16383:master@7302(online) replica@7304(online)
我第一次查询时(集群刚建好、没有数据流过),CLUSTER SLOTS 只返回主库、没有从库;CLUSTER SHARDS 显示从库的 health 是 loading。写入数据之后,两者都变成「主 + 从(online)」。所以刚建好的集群里,从库可能暂时不出现在槽位表里——依赖 CLUSTER SLOTS 做读写分离的客户端要注意(我没有深究 loading 的判定规则,只观察到了这个现象)。
平均 6.10 个/槽,最小 0,最大 13,标准差 2.76(若是完全随机的泊松分布,标准差应约 2.47) 抽查 5 个槽(槽号, 自己算的 key 数, CLUSTER COUNTKEYSINSLOT): [(0, 7, 7), (5460, 7, 7), (5461, 4, 4), (10922, 3, 3), (16383, 5, 5)]
10 万个 key 分布在 16384 个槽里,平均每槽 6.10 个,最少 0、最多 13,标准差 2.76。如果 key 是完全随机地落到槽里,标准差应约 2.47;实际略大,说明这批规则的 key 名(user:数字)在槽里的分布比纯随机稍散——但整体仍然很均匀(最大 13 vs 平均 6.1)。抽查的 5 个槽,CLUSTER COUNTKEYSINSLOT 返回的数与我自己用 CRC16 算出来的完全一致。
127.0.0.1:7300 (b17c901b...) -> 33359 keys | 5461 slots | 1 slaves.
127.0.0.1:7302 (3b88246a...) -> 33352 keys | 5461 slots | 1 slaves.
127.0.0.1:7301 (3625acd4...) -> 33289 keys | 5462 slots | 1 slaves.
[OK] 100000 keys in 3 masters.
6.10 keys per slot on average.
>>> Performing Cluster Check (using node 127.0.0.1:7300)
M: b17c901b5d2d24edfbf3cce1ca1e59cc6ef38969 127.0.0.1:7300
slots:[0-5460] (5461 slots) master
1 additional replica(s)
S: b910752392a99299b28f8e06c8a327f88e241bba 127.0.0.1:7303
slots: (0 slots) slave
replicates 3625acd442688c68fb1aebb769a9f111085bf81b
S: e1ff2e34b9e0538a57265b5a56d1505b387259d2 127.0.0.1:7305
slots: (0 slots) slave
replicates b17c901b5d2d24edfbf3cce1ca1e59cc6ef38969
M: 3b88246a9e397542ef4b11f3fa0583038bda3a97 127.0.0.1:7302
slots:[10923-16383] (5461 slots) master
1 additional replica(s)
S: 244080767126b4fe80176f73bc4644ef8bb6365c 127.0.0.1:7304
slots: (0 slots) slave
replicates 3b88246a9e397542ef4b11f3fa0583038bda3a97
M: 3625acd442688c68fb1aebb769a9f111085bf81b 127.0.0.1:7301
slots:[5461-10922] (5462 slots) master
1 additional replica(s)
[OK] All nodes agree about--cluster check 汇总:每个主库的 key 数、槽数、从库数;「All 16384 slots covered」表示所有槽都有主库负责。