为什么RedisCluster设计成16384个槽


Posted in Redis onSeptember 25, 2021

亲爱的同学们,你是否使用过Redis集群呢?那Redis集群的原理又是什么呢?记住下面两句话:

  • Redis Sentinal着眼于高可用,在master宕机时会自动将slave提升为master,继续提供服务。
  • Redis Cluster着眼于扩展性,在单个redis内存不足时,使用Cluster进行分片存储。

一、数据分片策略

布式数据存储方案中最为重要的一点就是数据分片,也就是所谓的 Sharding。为了使得集群能够水平扩展,首要解决的问题就是如何将整个数据集按照一定的规则分配到多个节点上,常用的数据分片的方法有:范围分片,哈希分片,一致性哈希算法和虚拟哈希槽等。

范围分片假设数据集是有序,将顺序相临近的数据放在一起,可以很好的支持遍历操作。范围分片的缺点是面对顺序写时,会存在热点。比如日志类型的写入,一般日志的顺序都是和时间相关的,时间是单调递增的,因此写入的热点永远在最后一个分片。对于关系型的数据库,因为经常性的需要表扫描或者索引扫描,基本上都会使用范围的分片策略。

我们为了将不同的 key 分散放置到不同的 redis 节点,通常的做法是获取 key 的哈希值,然后根据节点数来求模,但这种做法有其明显的弊端,当我们需要增加或减少一个节点时,会造成大量的 key 无法命中,这种比例是相当高的,所以就有人提出了一致性哈希的概念。

一致性哈希有四个重要特征:

  • 均衡性:也有人把它定义为平衡性,是指哈希的结果能够尽可能分布到所有的节点中去,这样可以有效的利用每个节点上的资源。
  • 单调性:当节点数量变化时哈希的结果应尽可能的保护已分配的内容不会被重新分派到新的节点。
  • 分散性和负载:这两个其实是差不多的意思,就是要求一致性哈希算法对 key 哈希应尽可能的避免重复。

二、Redis的分片机制

但是:Redis 集群没有使用一致性hash, 而是引入了哈希槽的概念。

Redis Cluster 采用虚拟哈希槽分区,所有的键根据哈希函数映射到 0 ~ 16383 整数槽内,每个key通过CRC16校验后对16384取模来决定放置哪个槽(Slot),每一个节点负责维护一部分槽以及槽所映射的键值数据。

计算公式:slot = CRC16(key) & 16383。

这种结构很容易添加或者删除节点,并且无论是添加删除或者修改某一个节点,都不会造成集群不可用的状态。使用哈希槽的好处就在于可以方便的添加或移除节点。

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

三、Redis 虚拟槽分区的特点

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

为什么RedisCluster设计成16384个槽

 

四、 Redis 集群伸缩的原理

Redis 集群提供了灵活的节点扩容和收缩方案。在不影响集群对外服务的情况下,可以为集群添加节点进行扩容也可以下线部分节点进行缩容。可以说,槽是 Redis 集群管理数据的基本单位,集群伸缩就是槽和数据在节点之间的移动。

1.集群扩容

当一个 Redis 新节点运行并加入现有集群后,我们需要为其迁移槽和数据。首先要为新节点指定槽的迁移计划,确保迁移后每个节点负责相似数量的槽,从而保证这些节点的数据均匀。

  • 首先启动一个 Redis 节点,记为 M4。
  • 使用 cluster meet 命令,让新 Redis 节点加入到集群中。新节点刚开始都是主节点状态,由于没有负责的>槽,所以不能接受任何读写操作,后续我们就给他迁移槽和填充数据。
  • 对 M4 节点发送 cluster setslot { slot } importing { sourceNodeId } 命令,让目标节点准备导入槽的数据。 >4) 对源节点,也就是 M1,M2,M3 节点发送 cluster setslot { slot } migrating { targetNodeId } 命令,让源节>点准备迁出槽的数据。
  • 源节点执行 cluster getkeysinslot { slot } { count } 命令,获取 count 个属于槽 { slot } 的键,然后执行步骤>六的操作进行迁移键值数据。
  • 在源节点上执行 migrate { targetNodeIp} " " 0 { timeout } keys { key... } 命令,把获取的键通过 pipeline 机制>批量迁移到目标节点,批量迁移版本的 migrate 命令在 Redis 3.0.6 以上版本提供。
  • 重复执行步骤 5 和步骤 6 直到槽下所有的键值数据迁移到目标节点。
  • 向集群内所有主节点发送 cluster setslot { slot } node { targetNodeId } 命令,通知槽分配给目标节点。为了>保证槽节点映射变更及时传播,需要遍历发送给所有主节点更新被迁移的槽执行新节点。

为什么RedisCluster设计成16384个槽

2.集群收缩

收缩节点就是将 Redis 节点下线,整个流程需要如下操作流程。

  • 首先需要确认下线节点是否有负责的槽,如果是,需要把槽迁移到其他节点,保证节点下线后整个集群槽节点映射的完整性。
  • 当下线节点不再负责槽或者本身是从节点时,就可以通知集群内其他节点忘记下线节点,当所有的节点忘记改节点后可以正常关闭。

下线节点需要将节点自己负责的槽迁移到其他节点,原理与之前节点扩容的迁移槽过程一致。

为什么RedisCluster设计成16384个槽

迁移完槽后,还需要通知集群内所有节点忘记下线的节点,也就是说让其他节点不再与要下线的节点进行 Gossip 消息交换。

Redis 集群使用 cluster forget { downNodeId } 命令来讲指定的节点加入到禁用列表中,在禁用列表内的节点不再发送 Gossip 消息。

五、总结

Redis Cluster 是Redis的集群实现,内置数据自动分片机制,集群内部将所有的key映射到16384个Slot中,集群中的每个Redis Instance负责其中的一部分的Slot的读写。集群客户端连接集群中任一Redis Instance即可发送命令,当Redis Instance收到自己不负责的Slot的请求时,会将负责请求Key所在Slot的Redis Instance地址返回给客户端,客户端收到后自动将原请求重新发往这个地址,对外部透明。一个Key到底属于哪个Slot由crc16(key) % 16384 决定。

面试问题:为什么RedisCluster会设计成16384个槽呢?

这个问题,作者是给出了回答的!

地址如下:https://github.com/antirez/redis/issues/2576

作者原版回答如下: The reason is:

Normal heartbeat packets carry the full configuration of a node, that can be replaced in an idempotent way with the old in order to update an old config. This means they contain the slots configuration for a node, in raw form, that uses 2k of space with16k slots, but would use a prohibitive 8k of space using 65k slots.At the same time it is unlikely that Redis Cluster would scale to more than 1000 mater nodes because of other design tradeoffs.

So 16k was in the right range to ensure enough slots per master with a max of 1000 maters, but a small enough number to propagate the slot configuration as a raw bitmap easily. Note that in small clusters the bitmap would be hard to compress because when N is small the bitmap would have slots/N bits set that is a large percentage of bits set.

1.如果槽位为65536,发送心跳信息的消息头达8k,发送的心跳包过于庞大。

如上所述,在消息头中,最占空间的是myslots[CLUSTER_SLOTS/8]。 当槽位为65536时,这块的大小是:65536÷8÷1024=8kb因为每秒钟,redis节点需要发送一定数量的ping消息作为心跳包,如果槽位为65536,这个ping消息的消息头太大了,浪费带宽。

2.redis的集群主节点数量基本不可能超过1000个。

如上所述,集群节点越多,心跳包的消息体内携带的数据越多。如果节点过1000个,也会导致网络拥堵。因此redis作者,不建议redis cluster节点数量超过1000个。 那么,对于节点数在1000以内的redis cluster集群,16384个槽位够用了。没有必要拓展到65536个。

3.槽位越小,节点少的情况下,压缩率高

Redis主节点的配置信息中,它所负责的哈希槽是通过一张bitmap的形式来保存的,在传输过程中,会对bitmap进行压缩,但是如果bitmap的填充率slots / N很高的话(N表示节点数),bitmap的压缩率就很低。 如果节点数很少,而哈希槽数量很多的话,bitmap的压缩率就很低。

而16384÷8÷1024=2kb,怎么样,神奇不!

综上所述,作者决定取16384个槽,不多不少,刚刚好!

到此这篇关于为什么RedisCluster设计成16384个槽的文章就介绍到这了,更多相关RedisCluster 16384槽内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Redis 相关文章推荐
redis限流的实际应用
Apr 24 Redis
Redis持久化与主从复制的实践
Apr 27 Redis
redis 查看所有的key方式
May 07 Redis
基于Redis过期事件实现订单超时取消
May 08 Redis
Redis主从配置和底层实现原理解析(实战记录)
Jun 30 Redis
CentOS8.4安装Redis6.2.6的详细过程
Nov 20 Redis
Redis 中使用 list,streams,pub/sub 几种方式实现消息队列的问题
Mar 16 Redis
高并发下Redis如何保持数据一致性(避免读后写)
Mar 18 Redis
使用Redis做预定库存缓存功能
Apr 02 Redis
详解Redis的三种常用的缓存读写策略步骤
May 06 Redis
Redis入门基础常用操作命令整理
Jun 01 Redis
使用redis生成唯一编号及原理示例详解
Sep 15 #Redis
Redis读写分离搭建的完整步骤
Sep 14 #Redis
在项目中使用redis做缓存的一些思路
Redis RDB技术底层原理详解
Sep 04 #Redis
使用redis实现延迟通知功能(Redis过期键通知)
Redis集群新增、删除节点以及动态增加内存的方法
Sep 04 #Redis
Redis字典实现、Hash键冲突及渐进式rehash详解
Sep 04 #Redis
You might like
JavaScript中的关键字"VAR"使用详解 分享
2013/07/31 Javascript
javascript实现根据身份证号读取相关信息
2014/12/17 Javascript
JavaScript实现ASC转汉字及汉字转ASC的方法
2016/01/23 Javascript
详解JavaScript中this关键字的用法
2016/05/26 Javascript
BootStrap中Tab页签切换实例代码
2016/05/30 Javascript
ECMAScript6快速入手攻略
2016/07/18 Javascript
javascript学习笔记_浅谈基础语法,类型,变量
2016/09/19 Javascript
js实现漫天星星效果
2017/01/19 Javascript
JavaScript队列的应用实例详解【经典数据结构】
2017/04/12 Javascript
Express的HTTP重定向到HTTPS的方法
2018/06/06 Javascript
js数组去重的N种方法(小结)
2018/06/07 Javascript
微信小程序实现底部导航
2018/11/05 Javascript
jQuery实现的卷帘门滑入滑出效果【案例】
2019/02/18 jQuery
JS使用cookie保存用户登录信息操作示例
2019/05/30 Javascript
vue.js实现回到顶部动画效果
2019/07/31 Javascript
Node.js 在本地生成日志文件的方法
2020/02/07 Javascript
15分钟上手vue3.0(小结)
2020/05/20 Javascript
vue实现户籍管理系统
2020/05/29 Javascript
[01:33]真香警告!DOTA2勇士令状不朽珍藏Ⅱ饰品欣赏
2018/06/26 DOTA
Python求解平方根的方法
2015/03/11 Python
python使用sorted函数对列表进行排序的方法
2015/04/04 Python
Python实现的视频播放器功能完整示例
2018/02/01 Python
python merge、concat合并数据集的实例讲解
2018/04/12 Python
使用Python3内置文档高效学习以及官方中文文档
2019/05/19 Python
python实现图像高斯金字塔的示例代码
2020/12/11 Python
使用HTML5拍照示例代码
2013/08/06 HTML / CSS
大学生毕业求职找工作的自我评价
2013/09/29 职场文书
小加工厂管理制度
2014/01/21 职场文书
四年大学自我鉴定
2014/02/17 职场文书
美国留学经济担保书
2014/05/20 职场文书
2014年纠风工作总结
2014/12/08 职场文书
行政申诉状范文
2015/05/20 职场文书
关于车尾的标语大全
2015/08/11 职场文书
浅谈克隆 JavaScript
2021/11/02 Javascript
Python+OpenCV实现在图像上绘制矩形
2022/03/21 Python
Spring Boot优化后启动速度快到飞起技巧示例
2022/07/23 Java/Android