redis cluster个人梳理-鸡零狗碎

涉及知识点

  • 虚拟槽分区
  • 客户端路由
    1.moved重定向
    2.ask重定向
  • smart智能客户端
  • 多节点命令实现

1.虚拟槽分区

虚拟槽分区是Redis Cluster采用的分区方式

预设虚拟槽,每个槽就相当于一个数字,有一定范围。每个槽映射一个数据子集,一般比节点数大

步骤:

1.把16384槽按照节点数量进行平均分配,由节点进行管理
2.对每个key按照CRC16规则进行hash运算
3.把hash结果对16383进行取余
4.把余数发送给Redis节点
5.节点接收到数据,验证是否在自己管理的槽编号的范围
    如果在自己管理的槽编号范围内,则把数据保存到数据槽中,然后返回执行结果
    如果在自己管理的槽编号范围外,则会把数据发送给正确的节点,由正确的节点来把数据保存在对应的槽中
需要注意的是:Redis Cluster的节点之间会共享消息,每个节点都会知道是哪个节点负责哪个范围内的数据槽

2.客户端路由

2.1 moved异常

redis cluster个人梳理-鸡零狗碎

2.2 ask异常

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 importing <node_id> (node_id为源节点id)
    -- 来源节点执行 cluster setslot migrating <node_id> (node_id为接收节点id)

分布式下集群一致性问题:
参考: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

  • 两者都是客户端重定向;
  • moved 异常说明槽已经确定迁移;
  • ask 异常说明槽还在迁移中,客户端访问的键有可能在 source 节点,有可能在 target 节点;(因为一个槽可能对应多个key,所以迁移一个槽的时候,一部分key在source,一部分key在target

两种异常对客户端造成的挑战

  • 怎么一下就命中键值真实存在的节点;
  • 怎么保证性能?

redis cluster个人梳理-鸡零狗碎

上一篇:内部类


下一篇:矢量运算的一些模板(一)