依据哈希槽进行数据划分。
Redis 集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定key 对应哪个槽。
例如当前集群有3个节点,那么:
为了保证节点的高可用,通常采用主从模式,也既每个主节点都有从节点。
因此 Cluster 模式下集群高可用,需要 3 主 3 从。
redis 127.0.0.1:7000> set foo bar
-> Redirected to slot [12182] located at 127.0.0.1:7002
OK
猜测:
若是 server 帮忙将操作转发到正确的节点:
若是 client redirect:
相比之下,还是 client redirect 更实惠。
简单客户端 redis-cli 模式下有个问题,无法提前知道当前 key 对应的 slot 具体是在哪个节点,因此会产生很多 redirect。
JedisPool 是个 Java redis 连接池,它会缓存的对应关系,因此执行操作时,先计算 key 对应的 slot,再找到 slot 对应的节点。
因多个 key 可能对应多个 slot,进而多个 slot 分布在不同的节点上,因此 Cluster 模式通常不支持 multi keys 相关操作。
// 以 Java Redis 客户端 Jedis 为例:
// 对于 multi keys,要求所有的 key 都对应同一个 slot 才能执行(这个限制更严格,更宽松一点的限制是:可以对应多个 slot,但这些slot 都在一个节点上)
if (keys.length > 1) {
int slot = JedisClusterCRC16.getSlot(keys[0]);
for (int i = 1; i < keyCount; i++) {
int nextSlot = JedisClusterCRC16.getSlot(keys[i]); // 计算key对应的 slot
if (slot != nextSlot) { // slot 不一致则抛异常
throw new JedisClusterException("No way to dispatch this command to Redis Cluster "
+ "because keys have different slots.");
}
}
}
在有些场景下,我们希望多个 key 都在一个节点上,如何控制呢?
原因:
假设集群包含 A 、 B 、 C 、 A1 、 B1 、 C1 六个节点。
其中 A 、B 、C 为主节点, A1 、B1 、C1 为A,B,C的从节点。
还有一个客户端 Z1 。
假设集群中发生网络分区,那么集群可能会分为两方,
大部分的一方包含节点 A 、C 、A1 、B1 和 C1 ,
小部分的一方则包含节点 B 和客户端 Z1 。
Z1仍然能够向主节点B中写入,
如果网络分区发生时间较短,那么集群将会继续正常运作,
如果分区的时间足够让大部分的一方将B1选举为新的master,那么Z1写入B中得数据便丢失了。
添加节点,删除节点,重新分片,本质上都是一类操作:slot 迁移。
例如新加入节点,则将其他节点上的部分 slot 分配给新节点。
Cluster 模式下,数据迁移的基本单位是 slot。
slot 迁移步骤:
因 slot 迁移过程中,该 slot 里的 key 部分在 A 节点,部分在 B 节点,因此 client 的请求处理会发生很大变化。
为何重定向时不能直接用 get,而是先发一个 ask指令?
因为此时该slot还不属于节点 B(还是属于节点 A),直接发 get 命令,B 会把 client 重定向到 A,造成循环重定向