hash slot
redis cluster 有固定的 16384 个 hash slot,对每个 key 计算 CRC16 值,然后对 16384 取模,可以获取 key 对应的 hash slot。
HASH_SLOT = CRC16(key) mod 16384
为什么选择mod 16384呢?
In our tests CRC16 behaved remarkably well in distributing different kinds of keys evenly across the 16384 slots
官网说:在测试中发现,使用CRC16算法计算出来的key可以在16384个槽中均匀分布。
用一个例子看看hash slot是怎么实现的:
我们假设现在有3个节点已经组成了集群,分别是:A, B, C 三个节点,它们可以是一台机器上的三个端口,也可以是三台不同的服务器。那么,采用hash slot的方式来分配16384个slot 的话,它们三个节点分别承担的slot 区间是:
- 节点A覆盖0-5460;
- 节点B覆盖5461-10922;
- 节点C覆盖10923-16383.
v2-a1fd8ac5e0c77fd3d257fb0c5f0a71fd_720w.jpg
节点上使用bitmap记录各自的hash slot。
那么,现在我想设置一个key, 比如叫my_name
:
set my_name *****
hash slot:CRC16('my_name')%16384 = 2412
。 那么就会把这个key 的存储分配到 A 上了。
我想获取my_name
get my_name
会出现两种情况:
- client刚好直接访问到Node A,Node A查询自己的hash slot表,发现key->my_name在自己节点中,接着处理命令,获取my_name的值返回客户端。
- client访问到Node B或者Node C,发现key->my_name在Node A中,返回MOVED error。然后client重定向到该节点
GET my_name
-MOVED 2412 127.0.0.1:6381
ps: client也可以缓存各节点的hash slot map
新增一个Node D:
从各个节点的前面各拿取一部分slot到Node D上
- 节点A覆盖1365-5460
- 节点B覆盖6827-10922
- 节点C覆盖12288-16383
- 节点D覆盖0-1364,5461-6826,10923-12287
同样删除一个节点也是类似,移动完成后就可以删除这个节点了。