Redis 集群 - 数据分片算法

前言

        广义的集群:只要是多个机器构成了一个分布式系统,都可以被称为集群。

        狭义的集群:redis 的集群模式,这个集群模式下,主要是解决存储空间不足的问题。

Redis 集群

        redis 采用主从结构,可以提高系统的可用性,但是并不能解决存储空间不足的问题,因为主节点和从节点存储的都是全量数据,随着业务功能的逐步使用,存储数据的逐步增加,redis 由于内存的限制肯定会在某一时刻到达极限,无法存储过多的数据。

        我们要如何解决 redis 存储空间不足的问题呢?加机器即可!所谓 "⼤数据" 的核⼼, 其实就是⼀台机器搞不定了,⽤多台机器来搞,Redis 集群就是在上述的思路之下,引⼊多组 Master / Slave , 每⼀组 Master / Slave 存储数据全集的 ⼀部分, 从⽽构成⼀个更⼤的整体, 称为 Redis 集群。

        假定整个数据全集是 1 TB, 引⼊三组 Master / Slave 来存储. 那么每⼀组机器只需要存储整个 数据全集的 1/3 即可.

在上述图中

        • Master1 和 Slave11 和 Slave12 保存的是同样的数据.占总数据的 1/3

        • Master2 和 Slave21 和 Slave2 保存的是同样的数据.占总数据的 1/3

        • Master3 和 Slave31 和 Slave32 保存的是同样的数据.占总数据的 1/3

这三组机器存储的数据都是不同的.

        每个 Slave 都是对应 Master 的备份(当 Master 挂了, 对应的 Slave 会补位成 Master).每个红框部分都可以称为是⼀个 分⽚ (Sharding).如果全量数据进⼀步增加, 只要再增加更多的分⽚,即可解决.

数据分片算法

        Redis cluster 的核⼼思路是⽤多组机器来存数据的每个部分.那么接下来的核⼼问题就是,给定⼀个数据(⼀个具体的 key), 那么这个数据应该存储在哪个分⽚上?读取的时候⼜应该去哪个分⽚读取?

围绕这个问题,业界有三种⽐较主流的实现⽅式.

哈希求余

        借鉴了哈希表的基本思想,借助 hash 函数,将数据的 key 映射成整数,再针对分片片数求余,得到了一个下标,就可以把数据保存到该下标对应的分片上了,

ps:MD5 就是一个普遍用来将字符串映射成整数的哈希函数

        比如现在我们拥有 3 片 redis 分片,此时来了一个字符串,字符串映射为整数是 10,那么就需要将该数据保存到 10%3=1 号分片上,后续要获取该 key 所对应的数值时,也用同样的方法获取分片编号,再去编号对应的 redis 分片上获取数据即可。

优缺点

        优点:简单⾼效, 数据分配均匀

        缺点不方便扩容,⼀旦需要进⾏扩容, N (分片数)改变了,原有的映射规则被破坏,就需要让节点之间的数据相互传输,重新排列,以满⾜新的映射规则.此时需要搬运的数据量是⽐较多的,开销较⼤.

        ps:分片数改变以后,计算哪个数据保存到哪个分片的公式就改变了,按照新的公式,此时许多分片中现有的数据都在错误的位置,就要进行大批量的数据移动,这是非常消耗资源的行为。

用一个例子来直观的看待这个问题:

        如下图,N 为 3 的时候, [100, 120] 这 21 个 hash 值的分布 (此处假定计算出的 hash 值是⼀个简单的整数,⽅便⾁眼观察)

        当引⼊⼀个新的分⽚, N 从 3 => 4 时, ⼤量的 key 都需要重新映射.(某个key % 3 和 % 4 的结果不⼀样,就映射到不同机器上了).

        如上图可以看到,整个扩容⼀共 21 个 key, 只有 3 个 key 没有经过搬运,其他的 key 都是搬运过的,很显然搬运数据是个非常庞大的工程

⼀致性哈希算法

        为了降低上述的搬运开销,能够更⾼效扩容,业界提出了"⼀致性哈希算法". key 映射到分⽚序号的过程不再是简单求余了,⽽是改成以下过程:

第⼀步,把 0 -> 2^32-1 这个数据空间, 映射到⼀个圆环上.数据按照顺时针⽅向增⻓.

第⼆步,假设当前存在三个分⽚,就把分⽚放到圆环的某个位置上.

第三步,假定有⼀个 key, 计算得到 hash 值 H, 那么这个 key 映射到哪个分⽚呢? 规则很简单, 就是从 H 所在位置,顺时针往下找,找到的第⼀个分⽚,即为该 key 所从属的分⽚.

        这就相当于, N 个分⽚的位置, 把整个圆环分成了 N 个管辖区间. Key 的 hash 值落在某个区间内, 就归对应区间管理.

        在这个情况下, 如果扩容⼀个分⽚, 如何处理呢? 原有分⽚在环上的位置不动, 只要在环上新安排⼀个分⽚位置即可.

        此时,只需要把 0 号分片上的部分数据,搬运给 3 号分⽚即可.1 号分⽚和 2 号分⽚管理的区间都是不变的.

        但可以明显看出,我们只是减少了 0 号分片的压力,1 号分片和 2 号分片中存储的数据多于 0 号和 3 号分片。所以该方法存在数据分配不均匀的问题

优缺点

优点:⼤⼤降低了扩容时数据搬运的规模,提⾼了扩容操作的效率

缺点:数据分配不均匀(有的多有的少,数据倾斜).

哈希槽分区算法(Redis 使用)

        为了解决上述问题(搬运成本⾼和数据分配不均匀),Redis cluster 引⼊了哈希槽(hash slots) 算法

获取哈希槽编号

hash_slot = crc16(key) % 16384

其中 crc16 也是⼀种 hash 算法.

        相当于是把整个哈希值, 映射到 16384 个槽位上,也就是 [0, 16383].然后再把这些槽位⽐较均匀的分配给每个分片.每个分⽚的节点都需要记录⾃⼰持有哪些哈希槽

        假设当前有三个分⽚,⼀种可能的分配⽅式:

         • 0 号分⽚: [0, 5461], 共 5462 个槽位

        • 1 号分⽚: [5462, 10923], 共 5462 个槽位

        • 2 号分⽚: [10924,16383],共 5460 个槽位

        这⾥的分⽚规则是很灵活的.每个分⽚持有的槽位也不⼀定连续.每个分⽚的节点使⽤位图来表⽰⾃⼰持有哪些槽位.对于 16384 个槽位来说,需要 2048 个字节(2KB) ⼤⼩的内存空间表⽰.

        ⼀种可能的分配⽅式:

        • 0 号分⽚: [0,4095],共 4096 个槽位

        • 1 号分⽚:[5462,9557], 共 4096 个槽位

        • 2 号分⽚: [10924, 15019], 共 4096 个槽位

        • 3 号分⽚: [4096, 5461] + [9558, 10923] + [15019, 16383],共 4096 个槽位

        我们在实际使⽤ Redis 集群分⽚的时候, 不需要⼿动指定哪些槽位分配给某个分⽚,只需要告 诉某个分⽚应该持有多少个槽位即可,Redis 会⾃动完成后续的槽位分配, 以及对应的 key 搬运的⼯作.

此处还有两个问题:

问题⼀: Redis 集群是最多有 16384 个分⽚吗?

        并⾮如此. 如果⼀个分⽚只有⼀个槽位, 这对于集群的数据均匀其实是难以保证的. 实际上 Redis 的作者建议集群分⽚数不应该超过 1000

        ⽽且, 16000 这么⼤规模的集群, 本⾝的可⽤性也是⼀个⼤问题.⼀个系统越复杂,出现故障的概率是越⾼的.

问题⼆:为什么是 16384 个槽位?

        • 节点之间通过⼼跳包通信.⼼跳包中包含了该节点持有哪些 slots.这个是使⽤位图这样的数据结构 表⽰的.表⽰ 16384 (16k) 个 slots,需要的位图⼤⼩是 2KB. 如果给定的 slots 数更多了,⽐如 65536 个了,此时就需要消耗更多的空间,8 KB 位图表⽰了. 8 KB,对于内存来说不算什么,但是在频繁的⽹络⼼跳包中,还是⼀个不⼩的开销的

        • 另⼀⽅⾯, Redis 集群⼀般不建议超过 1000 个分⽚.所以 16k 对于最⼤ 1000 个分⽚来说是⾜够⽤ 的,同时也会使对应的槽位配置位图体积不⾄于很⼤.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/743699.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【FFmpeg】avformat_open_input函数

【FFmpeg】avformat_open_input函数 1.avformat_open_input1.1 初始化输入格式(init_input)1.1.1 文件路径判断格式(av_probe_input_format2)1.1.1.1 格式探测(read_probe)1.1.1.2 扩展匹配检查&#xff08…

【链表经典算法OJ题】(2)

4.链表的中间节点 单链表相关经典算法OJ题4: 链表的中间结点 . - 力扣(LeetCode). - 备战技术面试?力扣提供海量技术面试资源,帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。https://leetcode.cn/problem…

mmpose姿态估计

OpenMMLab GitHubOpenMMLab has 49 repositories available. Follow their code on GitHub.https://github.com/open-mmlab Installation — MMPose 1.3.1 documentationhttps://mmpose.readthedocs.io/en/latest/installation.html Body 3D Keypoint — MMPose 1.3.1 docume…

Linux_应用篇(27) CMake 入门与进阶

在前面章节内容中,我们编写了很多示例程序,但这些示例程序都只有一个.c 源文件,非常简单。 所以,编译这些示例代码其实都非常简单,直接使用 GCC 编译器编译即可,连 Makefile 都不需要。但是,在实…

关于导入springcloud项目一些jar加载不进去的问题处理

IntelliJ IDEA的Maven项目有时候通过右边Maven Projects面板的package或者install命令打包的时候,会报错导致打包失败,这是由于这两个命令打包前默认会运行tests测试,若测试失败则打包失败。但是有时候我们打包的时候一些项目配置是针对生产环…

Studio One 6.6.2中文破解版安装图文激活教程

Studio One 6.6.2中文破解版做为新生代音乐工作站,凭借更低的价格和完备的功能,获得了音乐人和直播行业工作者的青睐,尤其是对硬件声卡的适配支持更好,特别适合用来配合线上教学和电商带货。 最近网上出现不少关于StudioOne不能用…

吃鸡报错:请重新安装软件xinput1_3.dll怎么办,分享几种靠谱的解决方法

xinput1_3.dll 是 Microsoft DirectX 的一个重要组件,主要用于处理游戏控制器和其他输入设备的交互操作。当运行支持 DirectX 的游戏或程序时,xinput1_3.dll 文件会被操作系统加载到内存中,以提供输入设备的相关功能。如果 xinput1_3.dll 文件…

51单片机STC89C52RC——8.1 8*8 LED点阵模块(点亮一个LED)

目录 目的/效果 一,STC单片机模块 二,8*8 LED点阵模块 2.1 电路图 2.1.1 8*8 点阵模块电路图 2.1.2 74HC595(串转并)模块 电路图 2.1.3 芯片引脚 2.2 引脚电平分析 2.3 74HC595 串转并模块 2.3.1 装弹(移位…

计算机网络之入门

1.网络的发展 1.1计算机网络定义 计算机网络是以共享资源(硬件、软件和数据等)为目的而连接起来的、在协议控制下,由一台或多台计算机、若干台终端设备、数据传输设备等组成的系统之集合。 这些计算机系统应当具有独立自治的能力&#xff…

PHP+laravel 生成word

此功能较为繁琐我会从源头讲起 首先是数据库设置,下面是我的数据库结构 合同模版表 CREATE TABLE contract_tpl (id bigint unsigned NOT NULL AUTO_INCREMENT,name varchar(191) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 合同名称,file varchar(191) COLL…

redis集群简单介绍及其搭建过程

Redis集群 1、哨兵模式 哨兵可以有多个,从服务器也可以有多个,从服务器也可以有多个,在Redis3.0以前的版本要实现集群一般是借助哨兵sentinel工具来监控master节点的状态,如果master节点异常,则会实现主从切换&#x…

WMV 视频格式怎么转换?WMV 视频为什么不流行了?

目前有越来越多的视频格式类型,如常见的 MP4、FLV、AVI 等等,而技术的演变也逐渐让一些常见的视频格式变的越来越少了。 今天我们一起来聊下 WMV 这个视频格式,让我们看看它的发展以及为什么现在越来越少人使用了。 什么是 WMV 视频格式&…

沙姆镜头标定与重建

沙姆定律( Scheimpflug principle)则可以保证测量平面的物体能够清晰成像, 因此能够起到调整景深区域位置的作用。Scheimpflug 镜头就是根据沙姆定律所设计的一种特殊的镜头,通过机械结构使镜头与相机本体发生一定程度的偏转&…

如何将本地的Django项目部署到阿里云服务器上?

场景:在本地的pycharm上已经写好了一个Django架构的网站,现在要把它放到公网上 一、阿里云服务器 选择云服务器ECS,新用户可以免费使用三个月 购买时选择预装宝塔面板 买好后,进入云服务器控制台 重置实例密码 远程连接至服务…

腰背肌筋膜炎的症状及治疗

腰背肌筋膜炎的症状 一、疼痛特点: 主要表现为腰背部弥漫性钝痛,尤以两侧腰肌及髂嵴上方更为明显。疼痛特点为晨起痛,日间轻,傍晚复重。长时间不活动或活动过度均可诱发疼痛,病程长,且因劳累及气候变化而发…

东南亚本地化游戏

通常,亚洲电子游戏市场首先与中国联系在一起。但最近,分析人士越来越关注一个邻近地区:东南亚。而且有充分的理由。 该地区包括中南半岛、马来群岛和邻近岛屿上的十一个国家。1967年,其中10个国家(除东帝汶外&#xf…

透明屏幕的魅力:为何它如此受欢迎

在科技日新月异的今天,透明屏幕技术以其独特的魅力和广泛的应用前景,逐渐成为了科技领域的一颗璀璨明星。从智能手机、平板电脑到大型显示屏,透明屏幕技术以其前所未有的视觉体验和实用性,赢得了广大消费者的喜爱。 一、透明屏幕的…

进阶篇07——InnoDB引擎介绍

概览 逻辑存储结构 架构 当执行增删改查操作时,操作的是缓冲区的数据,如果缓冲区里没有要操作的数据,就会从磁盘中读取数据加载到缓冲区中;缓冲区的数据会以一定的频率通过后台线程刷新到磁盘中永久存储。 内存结构 磁盘结构 后…

vue3 antv/g6 动态设置mode,让节点不可以拖动

1、查看一下官网的设置说明 G6 设置mode 默认模式: const graph new G6.Graph({container: div,width: 500,height: 500,modes: {default: [drag-node,drag-canvas],custom: [drag-canvas]} })默认情况下,我们定义的是default,然后创建节…

JavaWeb——MySQL:DML对表数据的修改

2.DML对表数据的修改 2.1 修改表的数据 (1) 修改单行单列 SQL语句:update 表名 set 列名1数值1 where 列名2数值2; 将sql_student表姓名为吕小布的那行,性别设置为女; (2) 修改单行多列 SQL语句:update 表名 set 列…