为什么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 集群伸缩原理
May 15 Redis
Redis高级数据类型Hyperloglog、Bitmap的使用
May 24 Redis
k8s部署redis cluster集群的实现
Jun 24 Redis
redis不能访问本机真实ip地址的解决方案
Jul 07 Redis
在redisCluster中模糊获取key方式
Jul 09 Redis
SpringBoot整合Redis入门之缓存数据的方法
Nov 17 Redis
Redis超详细讲解高可用主从复制基础与哨兵模式方案
Apr 07 Redis
浅谈Redis的事件驱动模型
May 30 Redis
Redis特殊数据类型bitmap位图
Jun 01 Redis
Redis批量生成数据的实现
Jun 05 Redis
Redis sentinel哨兵集群的实现步骤
Jul 15 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
基于OpenCV的PHP图像人脸识别技术
2009/10/11 PHP
详解PHP中的null合并运算符
2015/12/30 PHP
php在windows环境下获得cpu内存实时使用率(推荐)
2018/02/08 PHP
PHP基于pdo的数据库操作类【可支持mysql、sqlserver及oracle】
2018/05/21 PHP
PHP实现数组根据某个单元字段排序操作示例
2018/08/01 PHP
laravel 解决Eloquent ORM的save方法无法插入数据的问题
2019/10/21 PHP
TP5框架使用QueryList采集框架爬小说操作示例
2020/03/26 PHP
js 发个判断字符串是否为符合标准的函数
2009/04/27 Javascript
JS 显示当前日期与时间的代码
2010/03/24 Javascript
JQuery文本框高亮显示插件代码
2011/04/02 Javascript
js单独获取一个checkbox看其是否被选中
2014/09/22 Javascript
JS基于FileSystemObject创建一个指定路径的TXT文本文件
2015/08/05 Javascript
javascript判断图片是否加载完成的方法推荐
2016/05/13 Javascript
xtemplate node.js 的使用方法实例解析
2016/08/22 Javascript
通过函数作用域和块级作用域看javascript的作用域链
2018/08/05 Javascript
JavaScript解析JSON数据示例
2019/07/16 Javascript
Python 类与元类的深度挖掘 II【经验】
2016/05/06 Python
Python+OpenCV人脸检测原理及示例详解
2020/10/19 Python
用python与文件进行交互的方法
2018/03/01 Python
Pycharm新建模板默认添加个人信息的实例
2019/07/15 Python
Python实现直播推流效果
2019/11/26 Python
使用python创建Excel工作簿及工作表过程图解
2020/05/27 Python
python中return如何写
2020/06/18 Python
Anaconda的安装与虚拟环境建立
2020/11/18 Python
Bogner美国官网:滑雪服中的”Dior”
2018/01/30 全球购物
马来西亚和新加坡巴士票在线预订:CatchThatBus
2018/11/17 全球购物
澳大利亚最大的护发和护肤品购物网站:RY
2019/12/26 全球购物
StubHub中国:购买和出售全球活动门票
2020/01/01 全球购物
高中数学教师求职信
2013/10/30 职场文书
采购经理岗位职责
2014/02/16 职场文书
超市活动计划书
2014/04/24 职场文书
电工技术比武方案
2014/05/11 职场文书
开平碉楼导游词
2015/02/06 职场文书
小学生暑假安全公约
2015/07/14 职场文书
怎样写工作总结啊!
2019/06/18 职场文书
python tkinter实现定时关机
2021/04/21 Python