vlambda博客
学习文章列表

redis集群版slot原理精华

免责声明

以下知识来源: https://juejin.im/post/5ce7efef518825332b59f79b

slot架构图

redis中slot和节点的对应关系图: 

  • 只要是redis集群版,slot的个数一定是16384个!

  • 数据库中的每个键都属于这16384个槽的其中一个,集群中的每个节点可以处理0个或者最多16384个槽;

  • Redis Cluster 采用虚拟哈希槽分区,所有的键根据哈希函数映射到 0 ~ 16383 整数槽内,计算公式:slot = CRC16(key) & 16383。每一个节点负责维护一部分槽以及槽所映射的键值数据。

Redis 虚拟槽分区的特点:

解耦数据和节点之间的关系,简化了节点扩容和收缩难度。节点自身维护槽的映射关系,不需要客户端或者代理服务维护槽分区元数据 支持节点、槽和键之间的映射查询,用于数据路由,在线集群伸缩等场景。

为什么是16384个slot?

  • 16384,即2的14次方;

  • 作者的回答:https://github.com/antirez/redis/issues/2576

  • 博主的分析:https://www.cnblogs.com/rjzheng/p/11430592.html

简单的说:

  • 为了保证集群的可靠性,redis cluster内部节点之间会发送ping/pong心跳包;

  • 每秒单节点发出ping消息数量 = 1 + 10*num(node.pong_received>cluster_node_timeout/2),其中node.pong_received是节点最近一次收到心跳包的时间间隔;有这个公式可以看出,心跳频率不低;

  • 当槽数为65536时,心跳包的大小会达到8k;如果是18364,心跳包的大小就只有2k;所以槽数越大时,带宽占用越大;

  • 另一方面,由于redis单节点性能可以很高,读有上万QPS、写也有800QPS;很少有需要节点数超过1000的情况;

  • 所以出于以上的trade-off,槽数为16384已经是够用了。

集群不可用

默认情况下,当集群 16384 个槽任何一个没有指派到节点时整个集群不可用。执行任何键命令返回 CLUSTERDOWN Hash slot not served 命令。当持有槽的主节点下线时,从故障发现到自动完成转移期间整个集群是不可用状态,对于大多数业务无法忍受这情况,因此建议将参数 cluster-require-full-coverage 配置为 no ,当主节点故障时只影响它负责槽的相关命令执行,不会影响其他主节点的可用性。

客户端路由

  • 客户端根据本地 slot 缓存发送命令到源节点,如果存在键对应则直接执行并返回结果给客户端。

  • 如果节点返回 MOVED 错误,更新本地的 slot 到 Redis 节点的映射关系,然后重新发起请求。

  • 如果数据正在迁移中,节点会回复 ASK 重定向异常。格式如下: ( error ) ASK { slot } { targetIP } : {targetPort}

  • 客户端从 ASK 重定向异常提取出目标节点信息,发送 asking 命令到目标节点打开客户端连接标识,再执行键命令。

ASK 和 MOVED 虽然都是对客户端的重定向控制,但是有着本质区别。ASK 重定向说明集群正在进行 slot 数据迁移,客户端无法知道什么时候迁移完成,因此只能是临时性的重定向,客户端不会更新 slot 到 Redis 节点的映射缓存。但是 MOVED 重定向说明键对应的槽已经明确指定到新的节点,因此需要更新 slot 到 Redis 节点的映射缓存。

腾讯云redis架构图

  • 中间是proxy层,也就是真正的redis集群的客户端。扩容时注意proxy也要扩容

  • proxy的主要功能:1.请求转发;2.数据组包;3.key和slot对应关系缓存和更新;

  • 图中集群共4个节点,1主3从;

  • 每个节点是24分片,每个分片对应 1个cpu + 指定内存;

集群版扩缩容

分片的新增和删除操作,系统将自动均衡 Slot 配置,并且迁移数据,迁移操作可能会失败,建议在业务低峰期进行操作, 避免迁移操作对业务访问造成影响。