虚拟槽分区是Redis Cluster采用的分区方式
预设虚拟槽,每个槽就相当于一个数字,有一定范围。每个槽映射一个数据子集,一般比节点数大
步骤:
1.把16384槽按照节点数量进行平均分配,由节点进行管理 2.对每个key按照CRC16规则进行hash运算 3.把hash结果对16383进行取余 4.把余数发送给Redis节点 5.节点接收到数据,验证是否在自己管理的槽编号的范围 如果在自己管理的槽编号范围内,则把数据保存到数据槽中,然后返回执行结果 如果在自己管理的槽编号范围外,则会把数据发送给正确的节点,由正确的节点来把数据保存在对应的槽中 需要注意的是:Redis Cluster的节点之间会共享消息,每个节点都会知道是哪个节点负责哪个范围内的数据槽
ask异常:客户端访问了正在迁移的键值对会得到 ask 异常,ask 异常会告诉访问的键值迁移到哪了,客户端再据此访问目标节点;
127.0.0.1:6380> keys *{info}* 1) "user:{info}:name" 2) "user:{info}:email" 3) "user:{info}:id" 4) "user:{info}:age" 127.0.0.1:6380> cluster keyslot *{info}* (integer) 5642
相关命令
cluster keyslot hello: 获取"hello"这个key是哪个槽
cluster nodes:获取槽所在节点的信息,就可以知道键所在的节点信息。
redis-cli时,可以加上-c参数,这样redis会自动帮我们连接到正确的节点执行命令。
hash_tag: 如果键中包含{},则集群在计算槽时会使用{}内的内容,而不是整个键,{}内的内容又称为hash_tag。它提供不同的键拥有相同的slot功能,通常用于redis IO优化。
CLUSTER SETSLOT [slot] migrating [destination-node-id]
CLUSTER SETSLOT [slot] importing [source-node-id]
-- 接收节点执行 cluster setslot
-- 来源节点执行 cluster setslot
分布式下集群一致性问题:
参考:Redis Cluster 集群一致性原理及slot迁移测试
在使用gossip协议中, 如果多个节点声称不同的集群信息, 那对于某个节点来说究竟要相信谁呢? Redis Cluster规定了每个主节点的epoch都不可以相同. 而一个节点只会去相信拥有更大node epoch的节点声称的信息, 因为更大的epoch代表更新的集群信息.
原则上:
(1)如果epoch不变, 集群就不应该有变更(包括选举和迁移槽位)
(2)每个节点的node epoch都是独一无二的
(3)拥有越高epoch的节点, 集群信息越新
slot 管理
首先我们搞清楚slot究竟是怎么管的. 每个节点都有一份16384长的表对应每个slot究竟归哪个节点, 并且会保存当前节点所认为的其它节点的node epoch. 这样每个slot实际上绑定了一个节点及其node epoch. 然后由自认为拥有某slot的节点来负责通知其它节点这个slot的归属. 其它节点收到这个消息后, 会对比该slot原先绑定节点的node epoch, 如果收到的是更大的node epoch则更新, 否则不予理睬. 除此之外, 除了使用slot相关命令做变更, 集群没有其它途径修改slot的归属.
slot x 是我管的, 我的node epoch是 y node A ------------------------------> node B (原来slot x归node C管, 如果 y 比 node C 的node epoch大, 我就更新slot x的归属)
这实际上依赖上述的原则(3), 并且相信slot的旧主人还没有更新epoch.
moved 和 ask
两种异常对客户端造成的挑战