redis-集群切片

news2024/12/23 13:47:31

切片集群

我曾遇到过这么一个需求:要用 Redis 保存 5000 万个键值对,每个键值对大约是 512B,为了能快速部署并对外提供服务,我们采用云主机来运行 Redis 实例,那么,该如何选择云主机的内存容量呢?

在使用的过程中,我发现,Redis 的响应有时会非常慢。后来,我们使用 INFO 命令查看 Redis 的 latest_fork_usec 指标值(表示最近一次 fork 的耗时),结果显示这个指标值特别高,快到秒级别了。这跟 Redis 的持久化机制有关系。在使用 RDB 进行持久化时,Redis 会 fork 子进程来完成,fork 操作的用时和 Redis 的数据量是正相关的,而 fork 在执行时会阻塞主线程。数据量越大,fork 操作造成的主线程阻塞的时间越长。所以,在使用 RDB 对 25GB 的数据进行持久化时,数据量较大,后台运行的子进程在 fork 创建时阻塞了主线程,于是就导致 Redis 响应变慢了。
这个时候,我们注意到了 Redis 的切片集群。虽然组建切片集群比较麻烦,但是它可以保存大量数据,而且对 Redis 主线程的阻塞影响较小。
切片集群,也叫分片集群,就是指启动多个 Redis 实例组成一个集群,然后按照一定的规则,把收到的数据划分成多份,每一份用一个实例来保存;

在切片集群中,实例在为 5GB 数据生成 RDB 时,数据量就小了很多,fork 子进程一般不会给主线程带来较长时间的阻塞。采用多个实例保存数据切片后,我们既能保存 25GB 数据,又避免了 fork 子进程阻塞主线程而导致的响应突然变慢。在实际应用 Redis 时,随着用户或业务规模的扩展,保存大量数据的情况通常是无法避免的。而切片集群,就是一个非常好的解决方案。这节课,我们就来学习一下

Redis 数据量增多处理

Redis 应对数据量增多的两种方案:纵向扩展(scale up)和横向扩展(scale out)
在这里插入图片描述
纵向扩展:升级单个 Redis 实例的资源配置,包括增加内存容量、增加磁盘容量、使用更高配置的 CPU。就像下图中,原来的实例内存是 8GB,硬盘是 50GB,纵向扩展后,内存增加到 24GB,磁盘增加到 150GB。

横向扩展:横向增加当前 Redis 实例的个数,就像下图中,原来使用 1 个 8GB 内存、50GB 磁盘的实例,现在使用三个相同配置的实例。

  • 纵向扩展好处和缺点
    首先,纵向扩展的好处是,实施起来简单、直接。不过,这个方案也面临两个潜在的问题。第一个问题是,当使用 RDB 对数据进行持久化时,如果数据量增加,需要的内存也会增加,主线程 fork 子进程时就可能会阻塞(比如刚刚的例子中的情况)。不过,如果你不要求持久化保存 Redis 数据,那么,纵向扩展会是一个不错的选择。

  • 纵向扩展好处和缺点
    这时,你还要面对第二个问题:纵向扩展会受到硬件和成本的限制。这很容易理解,毕竟,把内存从 32GB 扩展到 64GB 还算容易,但是,要想扩充到 1TB,就会面临硬件容量和成本上的限制了。在面向百万、千万级别的用户规模时,横向扩展的 Redis 切片集群会是一个非常好的选择

数据切片后,在多个实例之间如何分布

客户端怎么确定想要访问的数据在哪个实例上?接下来,我们就一个个地解决
在这里插入图片描述

Redis Cluster 集群 哈希槽

从 3.0 开始,官方提供了一个名为 Redis Cluster 的方案,用于实现切片集群。Redis Cluster 方案中就规定了数据和实例的对应规则。
具体来说,Redis Cluster 方案采用哈希槽(Hash Slot,接下来我会直接称之为 Slot),来处理数据和实例之间的映射关系。在 Redis Cluster 方案中,一个切片集群共有 16384 个哈希槽,这些哈希槽类似于数据分区,每个键值对都会根据它的 key,被映射到一个哈希槽中。

首先根据键值对的 key,按照CRC16 算法计算一个 16 bit 的值;然后,再用这个 16bit 值对 16384 取模,得到 0~16383 范围内的模数,每个模数代表一个相应编号的哈希槽。

我们在部署 Redis Cluster 方案时,可以使用 cluster create 命令创建集群,此时,Redis 会自动把这些槽平均分布在集群实例上。例如,如果集群中有 N 个实例,那么,每个实例上的槽个数为 16384/N 个。
当然, 我们也可以使用 cluster meet 命令手动建立实例间的连接,形成集群,再使用 cluster addslots 命令,指定每个实例上的哈希槽个数。

在手动分配哈希槽时,需要把 16384 个槽都分配完,否则 Redis 集群无法正常工作

假设集群中不同 Redis 实例的内存大小配置不一,如果把哈希槽均分在各个实例上,在保存相同数量的键值对时,和内存大的实例相比,内存小的实例就会有更大的容量压力。遇到这种情况时,你可以根据不同实例的资源配置情况,使用 cluster addslots 命令手动分配哈希槽。

示意图中的切片集群一共有 3 个实例,同时假设有 5 个哈希槽,我们首先可以通过下面的命令手动分配哈希槽:实例 1 保存哈希槽 0 和 1,实例 2 保存哈希槽 2 和 3,实例 3 保存哈希槽 4。

redis-cli -h 172.16.19.3 –p 6379 cluster addslots 0,1
redis-cli -h 172.16.19.4 –p 6379 cluster addslots 2,3
redis-cli -h 172.16.19.5 –p 6379 cluster addslots 4

在集群运行的过程中,key1 和 key2 计算完 CRC16 值后,对哈希槽总个数 5 取模,再根据各自的模数结果,就可以被映射到对应的实例 1 和实例 3 上了

客户端如何定位数据

在定位键值对数据时,它所处的哈希槽是可以通过计算得到的,这个计算可以在客户端发送请求时来执行。但是,要进一步定位到实例,还需要知道哈希槽分布在哪个实例上。

一般来说,客户端和集群实例建立连接后,实例就会把哈希槽的分配信息发给客户端。但是,在集群刚刚创建的时候,每个实例只知道自己被分配了哪些哈希槽,是不知道其他实例拥有的哈希槽信息的。

那么,客户端为什么可以在访问任何一个实例时,都能获得所有的哈希槽信息呢?这是因为,Redis 实例会把自己的哈希槽信息发给和它相连接的其它实例,来完成哈希槽分配信息的扩散。当实例之间相互连接后,每个实例就有所有哈希槽的映射关系了;

客户端收到哈希槽信息后,会把哈希槽信息缓存在本地。当客户端请求键值对时,会先计算键所对应的哈希槽,然后就可以给相应的实例发送请求了。

Redis 集群hash在分配

实例和哈希槽的对应关系并不是一成不变的,实例和哈希槽的对应关系并不是一成不变的,最常见的变化有两个(由于负载均衡)

集群中,实例有新增或删除,Redis 需要重新分配哈希槽;为了负载均衡,Redis 需要把哈希槽在所有实例上重新分布一遍。

实例之间还可以通过相互传递消息,获得最新的哈希槽分配信息,但是,客户端是无法主动感知这些变化的。这就会导致,它缓存的分配信息和最新的分配信息就不一致了,那该怎么办呢?
Redis Cluster 方案提供了一种重定向机制,所谓的“重定向”,就是指,客户端给一个实例发送数据读写操作时,这个实例上并没有相应的数据,客户端要再给一个新实例发送操作命令。

那客户端又是怎么知道重定向时的新实例的访问地址呢?当客户端把一个键值对的操作请求发给一个实例时,如果这个实例上并没有这个键值对映射的哈希槽,那么,这个实例就会给客户端返回下面的 MOVED 命令响应结果,这个结果中就包含了新实例的访问地址

GET hello:key
(error) MOVED 13320 172.16.19.5:6379
其中,MOVED 命令表示,客户端请求的键值对所在的哈希槽 13320,实际是在 172.16.19.5 这个实例上。通过返回的 MOVED 命令,就相当于把哈希槽所在的新实例的信息告诉给客户端了。这样一来,客户端就可以直接和 172.16.19.5 连接,并发送操作请求了。

在 Redis 3.0 之前,Redis 官方并没有提供切片集群方案,但是,其实当时业界已经有了一些切片集群的方案,例如基于客户端分区的 ShardedJedis,基于代理的 Codis、Twemproxy 等。这些方案的应用早于 Redis Cluster 方案,在支撑的集群实例规模、集群稳定性、客户端友好性方面也都有着各自的优势,我会在后面的课程中,专门和你聊聊这些方案的实现机制,以及实践经验。这样一来,当你再碰到业务发展带来的数据量巨大的难题时,就可以根据这些方案的特点,选择合适的方案实现切片集群,以应对业务需求了。

hash链

原理简介:

每个数据存储进来的时候,要根据hash算法,进行算值取余,存入到对应的机器中。取数据的时候,用同样的hash算法对key进行计算,即可取出数据。

应用场景:

Redis集群扩容或宕机缩减,那么就需要进行全库数据的重洗,hash取模的值调整。这样,就比较耗费时间。所以,该方案,要预先估计一下自己公司业务的数据量多大,服务器的存储能力多大,然后,考虑在扩容时,所需的时间多久,只要在允许的时间范围内,能够完成重洗数据,那就可以采取该方案。该方案的一个好处就是,简单。存数据简单,取数据简单,理解容易。

hash环

原理简介

上面说的Hash链,只经过了1次hash,即把key hash到对应的机器编号。
而Hash环有2次Hash:
(1)把所有机器编号hash到这个环上
(2)把key也hash到这个环上。然后在这个环上进行匹配,看这个key和哪台机器匹配。这样,每个机器负责对应段上的数据。

应用场景

当hash链性能满足不了公司业务数据量的时候,就要采取该方案进行性能提升。
当服务器缩减时,对应段数据向下游转移即可,这样,就不会影响到其他段服务器的数据。
当服务器扩容时,对应服务器下游的服务器数据要进行重洗,把部分数据转移到新扩容的服务器上即可。这样,在查找时,按照最新的hash算法取余,即可取出对应的数据。
这相较于hash链,进行全库冲洗,还是节省了很多
也就是说,hash链和hash环,在新增服务器的时候,都是要冲洗数据的,只是,hash链是全库冲洗(算法复杂度是N),hash环是下游节点冲洗(算法复杂度是1)

那么会有道友问,我直接上第二种方案不就得了。这显然是不行的。

原因:
hash环是有大小的,它的特点是把hash链首尾相连,那么,假设你公司业务只有百万级数据量,你设置成一个hash环。假设,hash环周长是100,小厂有4台服务器,第一次可以人为均匀分布到环上,但是,如果业务量数据增加,导致需要扩容。这时候,如果你对hash环进行扩周长,如果不重新分配服务器在环上的位置,那就会出现数据倾斜问题,如果,重新均匀分布服务器在环上的位置,那么,就要全库重洗数据。所以,这样就和hash链没什么区别。还多出一个数据倾斜问题

那么有道友就说了,那我把hash环周长设置的超大。这样,不就可以减轻扩容时,数据倾斜问题的严重性了吗?并不是这样,当你保持环周长不变的前提下扩容的时候,数据倾斜和环的周长并没有关系。只是和你扩容的服务器策略有关,就是,假设第一次设置4台服务器,那么,你扩容的服务器必须是2的N次方台,这样才能人为的避免数据倾斜。那么,你小厂有这个实力吗?显然没有,不划算。

另外,你的环周长越大,也就意味着取余的除数越大,那么,计算取余的时间就越久,比如,你对2取余,口算即可。你对2的32次方取余,那就要多用很多时间,这样,随着积累,你浪费的时间就很多了。相对于公司业务,数据量不大,但是,损耗的计算时间却很多,那就很不划算了。所以,环的周长也是要考虑的点

所以,使用hash环算法,要考虑两点
1、公司自身实力,每次扩容需要的服务器数据量是:a*2^n。其中,a是第一次均匀分布的服务器数据量,n>=0的整数。这个扩容方法,解决数据倾斜问题。
2、hash环周长大小选择。周长越大,计算越耗费时间。所以,要根据公司业务量大小,选择合理的周长大小,不能太小,否则经常扩容,不能太大,浪漫每次的取余时间。
3、数据倾斜问题的本质,就在于服务器节点在环上的分布是否均匀还是密集。分布密集了,那就会出现数据倾斜问题。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【设计模式】第10节:结构型模式之“组合模式”

一、简介 组合模式:将一组对象组织成树形结构,将单个对象和组合对象都看做树中的节点,以统一处理逻辑,并且它利用树形结构的特点,递归地处理每个子树,依次简化代码实现。使用组合模式的前提在于&#xff0…

【数据结构与算法】JavaScript实现集合与字典

文章目录 一、集合结构1.1.简介1.2.代码实现1.3.集合间的操作 二、字典结构2.1.简介2.2.封装字典 一、集合结构 1.1.简介 集合比较常见的实现方式是哈希表,这里使用JavaScript的Object类进行封装。 集合通常是由一组无序的、不能重复的元素构成。 数学中常指的集…

记录linux运行服务提示报错/bin/java: 没有那个文件或目录

描述:在执行jar启动命令时候提示 没有/bin/java 这个文件或者目录;然后我vi /usr/bin/java,是存在该文件的;那到底是什么问题呢,该不是没有创建软连接吧? 1、执行下述命令先测试下软链接是否有创建 ln -s …

SpringCloud微服务保护方案解读

目录 服务雪崩定义 问题的产生 示例 雪崩产生的几种场景 解决方案 熔断模式 隔离模式(仓壁模式 ) 限流模式 超时处理 总结 服务保护技术对比 服务雪崩定义 我们都知道在微服务中,服务间调用关系错综复杂,一个微服务…

2023年中国特种运输现状及市场格局分析[图]

特种运输是使用特殊车辆、方案,将特种货物转移至需求地的过程。相对于常规货物,特种货物在本身特性(危险品、鲜活货物)、价值(贵重物品)、体积(超大货物)、重量(超重货物…

【AD9361 数字接口CMOS LVDSSPI】C 并行数据 LVDS

接上一部分,AD9361 数字接口CMOS &LVDS&SPI 目录 一、LVDS模式数据路径和时钟信号LVDS模式数据通路信号[1] DATA_CLK[2] FB_CLK[3] Rx_FRAME[4] Rx_D[5:0][5] Tx_FRAME[6]Tx_D[5:0][7] ENABLE[8] TXNRX系列 二、LVDS最大时钟速率和信…

JavaScript对象与原型:揭示编程世界的奥秘

目录 对象:万物皆对象 原型:共享和继承的基石 继承与原型链 对象与原型的关系 对象的创建 原型与原型链 原型继承 总结 在JavaScript中,对象是非常重要的概念之一。它们允许我们以一种结构化的方式存储和组织数据,并提供了…

【ROS教程demo】用C++创建一个ROS节点,发布指令使得小海龟做圆周运动

ROS创建节点发布命令使得小海龟做圆周运动 1.任务需求2.任务分析2.1发布方topic和msg2.2接收方topic和msg2.3目标明确!3.创建ROS节点3.1创建发布方节点pub_pose3.2创建订阅方节点sub_pose1.任务需求 创建一个节点,在其中实现一个订阅者和一个发布者,完成以下功能: 发布者:…

打造中国汽车出海新名片,比亚迪亮相东京车展

作为全球知名的国际车展,东京车展向来都被业界人士誉为“亚洲汽车风向标”。2023年10月25日,第47届东京车展(自2023年更名为“日本移动出行展”)在东京国际展览中心如期揭幕。 作为中国车企的代表品牌,比亚迪携海豹、海…

40基于MATLAB,使用模板匹配法实现车牌的识别。

基于MATLAB,使用模板匹配法实现车牌的识别。具体包括将原图灰度化,边缘检测,腐蚀操作,车牌区域定位,车牌区域矫正,二值化,均值滤波,切割,字符匹配,最终显示车…

【数据库】Python脚本实现数据库批量插入事务

背景介绍 在工作中可能会遇到需要批量插入的场景, 而批量插入的过程具有耗时长的特点, 再此过程很容易出现程序崩溃的情况.为了解决插入大量数据插入后崩溃导致已插入数据无法清理及未插入数据无法筛出的问题, 需要编写一个脚本记录已插入和未插入的数据, 并可以根据记录的数据…

阿里云服务linux系统CentOs8.5安装/卸载nginx1.15.9

说明:尝试使用CentOs8.5安装nginx1.9.9失败,make的时候报错了,后面降低版本为CentOs7.5安装成功了,参考文章:【精选】centos7安装nginx-1.9.9_linx centos nginx 1.9.9版本 nginx error log file: "/-CSDN博客 一、安装ngin…

Animator中Has Exit Time,融合时间

写这篇文章的原因是,发现有时候SetTrigger后动画没有切换,做实验找到了原因。 一、勾选了Has Exit Time 动画一定会在设定的时间才可能会切换到下个动画片段。 NormalAttack1-->NormalAttack2,结束时间设置0.5 NormalAttack1-->NormalAttack3,结…

什么是Immutable.js?它的作用是什么?

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅:探索Web开发的奇妙世界 欢迎来到前端入门之旅!感兴趣的可以订阅本专栏哦!这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…

Flask-SQLAlchemy事件钩子介绍

一、前言 前几天在搜资料的时候无意中看到有介绍SQLAlchemy触发器,当时感觉挺奇怪的,触发器不是数据库层面的概念吗,怎么flask-SQLAlchemy这个ORM框架会有这玩意。 二、SQLAlchemy触发器一个简单例子 考虑到效率博客表中有两个字段&#xf…

【设计模式】第15节:行为型模式之“职责链模式”

一、简介 职责链模式:将请求的发送和接收解耦,让多个接收对象都有机会处理这个请求。将这些接收对象串成一条链,并沿着这条链传递这个请求,直到链上的某个接收对象能够处理它为止。 二、优点 分离发送者和接受者易于扩展和维护…

SIT1028Q内置高压 LDO 本地互联网络(LIN)收发器

SIT1028Q 是一款内部集成高压 LDO 稳压源的本地互联网络( LIN )物理层收发器,可为外 部 ECU ( Electronic Control Unit )微控制器或相关外设提供稳定的 5V/3.3V 电源,该 LIN 收发器 符合 LIN 2…

如何构建 :毫末波 与 RIS 研究系统

入门系统 USRP 上下变频器 喇叭天线 可联系博主系统的具体情况; 系统详情 首先需要在USRP上运行一个通信系统,这个系统可以是简单的文本传输系统,用Simulink搭建一下就行了。更加复杂的系统可以用LabVIEW或者Simulink来搭建;…

力扣第968题 监控二叉树 c++ hard题 二叉树的后序遍历 + 模拟 + 贪心

题目 968. 监控二叉树 困难 相关标签 树 深度优先搜索 动态规划 二叉树 给定一个二叉树,我们在树的节点上安装摄像头。 节点上的每个摄影头都可以监视其父对象、自身及其直接子对象。 计算监控树的所有节点所需的最小摄像头数量。 示例 1: …

Linux解决nvcc -V出现的-bash: nvcc command not found问题

两种解决办法: 1、第一种直接在bashrc文件中添加本地cuda路径: vim ~/.bashrc 定位到内容末尾,最末尾 添加命令: export LD_LIBRARY_PATH/usr/local/cuda/lib export PATH$PATH:/usr/local/cuda/bin添加后激活 source ~/.bashrc…