为什么Redis集群有16384个槽?

 Redis集群通过引入16384个槽(slots)的概念来实现数据的分布式存储。

  这个是结论,

  在讨论具体的原因前,必须要清楚redis的集群的概念。

什么是Redis集群?

Redis集群是一种服务器Sharding(分片)技术,3.0版本开始正式提供。

Redis的哨兵模式基本已经可以实现高可用,读写分离 ,但是在这种模式下每台Redis服务器都存储相同的数据,很浪费内存,所以在redis3.0上加入了Cluster集群模式,实现了Redis的分布式存储,也就是说每台 Redis 节点上存储不同的内容。
  • (分片存储)Redis3.0加入了 Redis 的集群模式实现了数据的分布式存储,对数据进行分片,将不同的数据存储在不同的master节点上面,从而解决了海量数据的存储问题

  • (指令转换)Redis集群采用去中心化思想,没有中心节点的说法,对于客户端来说,整个集群可以看成一个整体,可以连接任意一个节点进行操作,就像操作单一Redis实例一样,不需要任何代理中间件,当客户端操作的key没有分配到该node上时,Redis会返回转向指令,指向正确的Redis节点

  • (主从和哨兵)Redis也内置了高可用机制,支持N个master节点,每个master节点都可以挂载多个slave节点,当master节点挂掉时,集群会提升它的某个slave节点作为新的master节点

图片

如上图所示,Redis集群可以看成多个主从架构组合起来的,每一个主从架构可以看成一个节点(其中,只有master节点具有处理请求的能力,slave节点主要是用于节点的高可用)

集群的数据分片​​​​​​​

前面讲到,Redis集群通过分布式存储的方式解决了单节点的海量数据存储的问题,对于分布式存储,需要考虑的重点就是如何将数据进行拆分到不同的Redis服务器上。常见的分区算法有hash算法、一致性hash算法,关于这些算法这里就不多介绍。

如果要实现 Redis 数据的分片,我们有三种方案。

1>普通hash算法

  • (客户端负载)第一种是在客户端实现相关的逻辑,例如用取模或者一致性哈希对key进行分片,查询和修改都先判断key的路由

    Jedis客户端提供了Redis Sharding的方案,并且支持连接池

    Sharded 分片的原理?怎么连接到某一个Redis服务:提供了一致性hash和md5散列两种hash算法,默认使用一致性hash算法。

    并且为了使得请求能均匀的落在不同的节点上,Sharded Jedis会使用节点的名称(如果节点没有名称使用默认名称)虚拟化出160个虚拟节点。也可以根据不同节点的weight,虚拟化出160,weight个节点

    当客户端访问redis时,首先根据key计算出其落在哪个节点上,然后找到节点的ip和端口进行连接访问

  • (中间代理负载)第二种是把做分片处理的逻辑抽取出来,运行一个独立的代理服务,客户端连接到这个代理服务,代理服务做请求的转发。

  • (服务端负载)

  • (服务端负载) 第三种就是基于服务端实现分为:普通hash算法,一致性hash算法,哈希槽Slot算法

  • 如果是希望数据分布相对均匀的话,可以考虑哈希后取模

  • 将key使用hash算法计算之后:hash(key)%N,根据余数,决定映射到那一个节点

  • 优点就是比较简单,属于静态的分片规则。但是一旦节点数量变化,新增或者减少,由于取模的 N 发生变化, 数据需要重新分布和迁移


    2>一致性hash算法

  • 把所有的哈希值空间组织成一个虚拟的圆环(哈希环),整个空间按顺时针方向组织。因为是环形空间,0 和 2^32-1 是重叠的(总共2^32个)

  1. 先根据机器的名称或者 IP计算哈希值

  2. 然后分布到哈希环中。查找时先根据key计算哈希值,得到哈希环中的位置

  3. 最后顺时针找到第一个大于等于该哈希值的第一个Node,就是数据存储的节点

  • 优点是在加入和删除节点时只影响相邻的两个节点

  • 缺点是加减节点会造成部分数据无法命中

  • 此外,针对于hash节点分散不均匀或者倾倒状态,采用一个节点分为多个虚拟节点做优化


  • 所以一般用于缓存,而且用于节点量大的情况下,扩容一般增加一倍节点保障数据负载均衡


   3>哈希槽Slot算法 

Redis 集群既没有用哈希取模,也没有用一致性哈希,而是用Hash槽来实现的。Redis集群创建了 16384 个槽(slot),每个节点负责一定区间的slot。

Redis集群的哈希槽的分区

  • Redis集群中有16384(2^14)个哈希槽(槽的范围是 0 -16383,哈希槽),将不同的哈希槽分布在不同的Redis节点上面进行管理,也就是说每个Redis节点只负责一部分区间的哈希槽。

  • 对数据进行操作的时候:

  • 集群会对使用CRC16算法对key进行计算并对16384取模 (slot = CRC16(key)%16384) 。】

  • 得到的结果就是Key-Value所放入的槽,通过这个槽值,去找对应的槽所对应的Redis节点

  • 然后直接到这个对应的节点上进行存取操作

  • 好处:(自动更新hash槽的映射数据关系)使用哈希槽的好处就在于可以方便的添加或者移除节点,并且无论是添加删除或者修改某一个节点,都不会造成集群不可用的状态

  • 当需要增加节点时,只需要把其他节点的某些哈希槽挪到新节点就可以了

  • 当需要移除节点时,只需要把移除节点上的哈希槽挪到其他节点就行了

    哈希槽分区的分析

集群的每个节点负责一部分hash槽,举个例子,比如当前集群有3个节点,那么

  • 节点 A 包含 0 到 5460 号哈希槽

  • 节点 B 包含 5461 到 10922 号哈希槽

  • 节点 C 包含 10923 到 16383 号哈希槽

这种结构很容易添加或者删除节点。

  • (1)如果我想新添加个节点 D , 我需要从节点 A, B, C 中得部分槽到 D 上

  • (2)如果我想移除节点 A ,需要将 A 中的槽移到 B 和 C 节点上,然后将没有任何槽的 A 节点从集群中移除即可

由于从一个节点将哈希槽移动到另一个节点并不会停止服务,所以无论添加删除或者改变某个节点的哈希槽的数量都不会造成集群不可用的状态

注意:key 与 slot 的关系是永远不会变的,会变的只有 slot 和 Redis 节点的关系

怎么让相关的数据落到同一个节点上?​​​​​​​

在key里面加入{hash tag}即可。Redis在计算槽编号的时候只会获取{}之间的字符串进行槽编号计算,这样由于上面两个不同的键,{}里面的字符串是相同的,因此他们可以被计算出相同的槽

客户端重定向

客户端连接到哪一台服务器?访问的数据不在当前节点上,怎么办?

比如在 7291 端口的 Redis 的 redis-cli 客户端操作:​​​​​​​

127.0.0.1:7291> set qs 1
(error) MOVED 13724 127.0.0.1:7293
  • 服务端返回 MOVED,也就是根据 key 计算出来的 slot 不归 7191 端口管理,而是 归 7293 端口管理,服务端返回 MOVED 告诉客户端去 7293 端口操作

  • 这个时候更换端口,用 redis-cli –p 7293 操作,才会返回 OK。这样客户端需要连接两次。或者用./redis-cli -c -p port 的命令(c 代表 cluster)自动重定向

新增或下线了 Master 节点,数据怎么迁移(重新分配)?

  • 因为 key 和 slot 的关系是永远不会变的,当新增了节点的时候,需要把原有的 slot 分配给新的节点负责,并且把相关的数据迁移过来。

  • 新增的节点没有哈希槽,不能分布数据,在原来的任意一个节点上执行。

redis-cli --cluster reshard 127.0.0.1:7291
  • 槽的迁移与指派命令:     

CLUSTER ADDSLOTS 0 1 2 3 4 ... 5000

输入需要分配的哈希槽的数量(比如 500),和哈希槽的来源节点(可以输入 all 或 者 id)

以上内容基本就是集群的全部内容,那么我们继续聊下redis集群为什么有16384个槽? 

  1. 平衡性能和灵活性:选择 16384 个槽是为了在管理上的便利性、数据分布的均匀性以及集群重新分片的灵活性之间寻找平衡。较小的槽数量会减少重分布灵活性,较大的槽数量则会增加管理的复杂度和数据移动的成本。

  2. 避免大规模数据迁移:通过较小的槽数量,当需要扩展或收缩集群时,可以减少因为节点变动导致的大规模数据迁移,使得集群能够更快地达到平衡状态。

  3. 提高故障转移速度:在发生节点故障时,较少的槽数量意味着较少的数据迁移,从而可以更快完成故障转移和恢复,保证集群的高可用性。

如何突破限制?

尽管 Redis 集群设计的 16384 个槽为集群的扩展和管理提供了便利,但在某些大规模应用场景下,可能需要进一步提高集群的管理效率或突破这个槽数量的限制。下面是几种可能的方法:

  1. 使用代理:通过引入代理层,如 Twemproxy 或 Redis Cluster Proxy,可以在客户端 Redis 集群之间提供一个抽象层从而在客户端看来像是在与一个单一的大容量 Redis 实例交互。这种方法可以在一定程度上隐藏槽数量的限制。

  2. 多集群部署在极端的大规模场景下,可以部署多个 Redis 集群,并在应用逻辑中分配不同的数据集到不同的集群。这种方式虽然增加了应用层的复杂性,但可以有效地扩展 Redis 的存储和处理能力。

  3. 自定义数据分片策略:在应用层实现自定义的数据分片逻辑,根据业务需求将数据分布到不同的 Redis 集群或节点上。这种方法需要开发者在应用层做更多的管理和维护工作,但提供了更大的灵活性。

总结

Redis 集群通过 16384 个槽的设计,在数据分布的均匀性、集群扩展的灵活性和管理的简便性之间找到了一种平衡。虽然这个设计对大多数应用来说已经足够,但在一些特殊场景下,通过使用代理、多集群部署或自定义数据分片策略等方法,可以在不改变 Redis 内部机制的情况下,进一步提高系统的规模和性能。

以上为全部内容。

  • 6
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值