Redis集群

目录

一, 集群及分片算法

1.1 什么是集群

1.2 数据分片算法

1. 哈希求余

 2. 一致性哈希算

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

二, 集群的故障处理

2.1 故障判定

2.2 故障迁移

三, 集群扩容

四, 集群缩容


一, 集群及分片算法

1.1 什么是集群

我们在Redis哨兵中学习了,哨兵+主从复制是为了提高系统的可用性,当主节点发生宕机了,可以自动进行恢复,但是并不能解决"数据极端情况下丢失"的问题,不能提高数据的存储容量,当我们存储的数据接近或者超过机器的无礼内存,这样的结构就难以胜任了,所以引入了集群的概念.

Redis集群就是在上述的思路之下,引入多组Master/Slave,每一组Master/Slave存储数据全集的一部分,从而构成一个更大的整体,称为Redis集群.

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

在上述图中:

  • Master1 和 Slave11 和 Slave12  保存的数据是同样的数据,占总数据的1/3
  • Master2 和 Slave21 和 Slave22  保存的数据是同样的数据,占总数据的1/3
  • Master3 和 Slave31 和 Slave32  保存的数据是同样的数据,占总数据的1/3

这三组机器存储的数据是不同的;每个Slave都是对应Master的备份(当Master挂了,对应的Slave会补位成Master),每个红框部分都可以称为是一个分片(Sharding),如果数量进一步增加,只要增加更多的分片,即可解决.

1.2 数据分片算法

Redis集群的核心思路是用多组机器来存数据的每个部分,那么接下来的核心问题就是,给定一个数据(一个具体的key),那么这个数据应该存储在哪个分片上?读取的时候又应该去哪个分片读取?围绕这个问题,业界有三种比较主流的实现方式.

1. 哈希求余

设有N个分片,使用[0,N-1]这样序号进行编号

针对某个给定的key,先计算hash值,再把得到的结果%N,得到的结果即为分片编号.

例如,N为3.给定key为hello,对hello计算hash值(比如使用md5算法),得到的结果为"bc4b2a76b9719d91",再把这个结果%3,结果为0,那么就把hello这个key放到0号分片上;实际工作涉及到的系统,计算hash的方式不一定是md5,但是思想是一致的.

后续如果要取某个key的记录,也是针对key计算hash,再对N求余,就可以找到对应的分片编号了.

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

缺点:一旦需要进行扩容,N就改变了,原有的映射规则被破坏,就需要让节点之间的数据相互传输,重新排列以满足昕的映射规则,此时需要搬运的数据量是比较多的,开销较大

N为3的时候,[100,120]这21个hash值的分布(此处假定计算出的hash值是一个简单的整数,方便肉眼观察),当引入一个新的分片,N从3->4时,大量的key都需要重新映射(某个key%3和%4的结果不一样,就映射到不同机器上了)

如上图可以看出,整个扩容一共21个key,只有3个key没有经过搬运,其他的key都是搬过的.

 2. 一致性哈希算

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

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

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

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

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

在这个情况下,如果扩容一个分片,如何处理呢?

原有分片在环上位置不动,只要在环上新安排一个分片位置即可.

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

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

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

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

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

hash_slot = crc16(key) % 16384

其中crc16也是一种hash算法,通过key计算出对应的key

16384 = 16 * 1024 也就是2^14

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

假设当前有三个分片,一种可能的分配方式:

  • 0号分片:[0,5461] 共5642个槽位
  • 1号分片:[5642,10923] 共5642个槽位
  • 2号分片:[10924,16383] 共5640个槽位

这里的分片规则是很灵活的,每个分片持有的槽位也不一定连续,每个分片的节点使用位图来表示自己持有哪些槽位,对于16384个槽位来说,需要2048个字节(2KB)大小的内存空间表示.

如果需要进行扩容,比如新增一个3号分片,就可以针对原有的槽位进行重新分配,比如可以把之前每个分片持有的槽位,各拿出一点,分给新分片,一种可能的分配方式:

  • 0号分片:[0,4095] 共4096个槽位
  • 1号分片:[5642,9557] 共4096个槽位
  • 2号分片:[10924,15019] 共4096个槽位
  • 3号分片:[4096,5461] + [9558,10923] + [15019,16383] 共4096个槽位

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

哈希槽分区算法的相关面试问题:

问题一:Redis集群是最多有16384个分片吗?

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

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

  • 节点之间通过⼼跳包通信.,⼼跳包中包含了该节点持有哪些 slots.,这个是使⽤位图这样的数据结构表⽰的.;表⽰ 16384 (16k) 个 slots,需要的位图⼤⼩是 2KB,如果给定的 slots 数更多了,⽐如 65536 个了,此时就需要消耗更多的空间,8 KB 位图表⽰了,8 KB,对于内存来说不算什么,但是在频繁的⽹络⼼跳包中,还是⼀个不⼩的开销;
  • 另⼀⽅⾯,Redis 集群⼀般不建议超过 1000 个分⽚,所以 16k 对于最⼤ 1000 个分⽚来说是⾜够⽤的,同时也会使对应的槽位配置位图体积不⾄于很⼤.

二, 集群的故障处理

2.1 故障判定

集群中的所有节点,都会周期性的使用心跳包进行通信

  1. 节点 A 给 节点 B 发送 ping 包, B 就会给 A 返回⼀个 pong 包. ping 和 pong 除了 message type属性之外, 其他部分都是⼀样的. 这⾥包含了集群的配置信息(该节点的id, 该节点从属于哪个分⽚,是主节点还是从节点, 从属于谁, 持有哪些 slots 的位图...).
  2. 每个节点, 每秒钟, 都会给⼀些随机的节点发起 ping 包, ⽽不是全发⼀遍. 这样设定是为了避免在节点很多的时候, ⼼跳包也⾮常多(⽐如有 9 个节点, 如果全发, 就是 9 * 8 有 72 组⼼跳了, ⽽且这是按照 N^2 这样的级别增⻓的).
  3. 当节点 A 给节点 B 发起 ping 包, B 不能如期回应的时候, 此时 A 就会尝试重置和 B 的 tcp 连接, 看能否连接成功. 如果仍然连接失败, A 就会把 B 设为 PFAIL 状态(相当于主观下线).
  4. A 判定 B 为 PFAIL 之后, 会通过 redis 内置的 Gossip 协议, 和其他节点进⾏沟通, 向其他节点确认 B的状态. (每个节点都会维护⼀个⾃⼰的 "下线列表", 由于视⻆不同, 每个节点的下线列表也不⼀定相同). ​​​​​​
  5. 此时 A 发现其他很多节点, 也认为 B 为 PFAIL, 并且数⽬超过总集群个数的⼀半, 那么 A 就会把 B 标记成 FAIL (相当于客观下线), 并且把这个消息同步给其他节点(其他节点收到之后, 也会把 B 标记成FAIL).

至此,B就彻底被判定为故障节点了.

某个或者某些节点宕机,有的时候会引起整个集群都宕机(称为fail状态),以下情况会出现集群宕机:

  • 某个分片,所有主节点和从节点都挂了
  • 某个分片上,主节点挂了,但是没有从节点
  • 超过半数的master节点都挂了

2.2 故障迁移

上述例子中,B故障,并且A把B FAIL 的消息告知集群中的其他节点

  • 如果B是从节点,那么不需要进行故障迁移
  • 如果B是主节点,那么就会由B 的从节点(比如C和D)出发故障迁移了

所谓故障迁移,就是指把从节点提拔成主节点,继续给整个Redis集群提供支持,具体流程如下:

  1. 从节点判定⾃⼰是否具有参选资格. 如果从节点和主节点已经太久没通信(此时认为从节点的数据和主节点差异太⼤了), 时间超过阈值, 就失去竞选资格
  2. 具有资格的节点, ⽐如 C 和 D, 就会先休眠⼀定时间. 休眠时间 = 500ms 基础时间 + [0, 500ms] 随机时间 + 排名 * 1000ms. offset 的值越⼤, 则排名越靠前(越⼩)​​​​​​
  3. ⽐如 C 的休眠时间到了, C 就会给其他所有集群中的节点, 进⾏拉票操作. 但是只有主节点才有投票资格
  4. 主节点就会把⾃⼰的票投给 C (每个主节点只有 1 票). 当 C 收到的票数超过主节点数⽬的⼀半, C 就会晋升成主节点. (C ⾃⼰负责执⾏ slaveof no one, 并且让 D 执⾏ slaveof C)​​​​​​​
  5. 同时, C 还会把⾃⼰成为主节点的消息, 同步给其他集群的节点. ⼤家也都会更新⾃⼰保存的集群结构信息

上述选举的过程,称为Raft算法,是一种在分布式系统中广泛使用的算法,在随机休眠时间的加持下,基本上就是谁先唤醒谁谁就能竞选成功.

三, 集群扩容

扩容是一个在开发中比较常遇到的场景,随着业务的发展,现有集群很可能无法容日益增长的数据,此时给集群中加入更多新的机器,就可以使存储空间更大了.

第一步:把新的主节点加入到集群

第二步:重现分配slots

在搬运key的过程中,对于那些不需要搬运的key,访问的时候是没有任何问题的,但是对于需要搬运的key,进行访问可能会出现短暂的访问错误(key的位置发生了变化),随着搬运完成,这样的错误自然就恢复了

第三步:给新的主节点添加从节点

光有主节点了,此时扩容的目标已经初步达成,但是为了保证集群可用性,还需要给这个新的主节点添加从节点,保证该主节点宕机之后,有从节点能够顶上

四, 集群缩容

扩容是比较常见的,但是缩容其实非常少见,此处简单说一下缩容的流程:

第一步:删除从节点

第二步:重新分配slots

第三步:删除主节点

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

并发编程(线程基础)

线程和进程的区别并发与并行的区别线程创建方式runnable和callable的区别run()和start()的区别线程包括哪些状态,状态之间如何变化新建三个线程,如何按顺序执行notify()和notifyAll()的区别wait和sleep方法的区别如何停止一个正在运行的线程 一、线程和进…

linux远程桌面管理工具xrdp

一、概述 我们知道,我们日常通过vnc来远程管理linux图形界面,今天分享一工具Xrdp,它是一个开源工具,允许用户通过Windows RDP访问Linux远程桌面。 除了Windows RDP之外,xrdp工具还接受来自其他RDP客户端的连接&#xf…

代码随想录Day36 动态规划05 LeetCode T1049最后一块石头的重量II T494 目标和 T474 一和零

前言 : 动规五部曲 理论基础 : 代码随想录Day34 LeetCode T343整数拆分 T96 不同的二叉搜索树-CSDN博客 1.明白dp数组的含义 2.明白递推公式的含义 3.初始化dp数组 4.注意dp数组的遍历顺序 5.打印dp数组排错 LeetCode T1049 最后一块石头的重量II 题目链接:1049. 最后一块石头…

多技术融合提升环境、生态、水文、土地、农业、大气等领域科研技术水平

专题一、空间数据获取与制图 1.1 软件安装与应用讲解 1.2 空间数据介绍 1.3海量空间数据下载 1.4 ArcGIS软件快速入门 1.5 Geodatabase地理数据库 点击查看原文链接https://mp.weixin.qq.com/s?__bizMzg2NDYxNjMyNA&mid2247546998&idx6&sn39342c376b158eff1…

坚持#第420天~阿里云轻量服务器内存受AliYunDunMonito影响占用解决方法

阿里云轻量服务器内存受AliYunDunMonito影响占用解决方法,亲测有效: Mobax好卡啊,那就直接在阿里云后台操作即可,阿里云后台也可以上传文件。 Navicat mysql好卡啊,那就直接在阿里云后台最上面帮助的右边有个数据库&…

使用Llama index构建多代理 RAG

检索增强生成(RAG)已成为增强大型语言模型(LLM)能力的一种强大技术。通过从知识来源中检索相关信息并将其纳入提示,RAG为LLM提供了有用的上下文,以产生基于事实的输出。 但是现有的单代理RAG系统面临着检索效率低下、高延迟和次优提示的挑战。这些问题在…

stable-diffusion 电商领域prompt测评集合

和GhostReivew一个思路,还是从比较好的图片或者是civitai上找一些热门的prompt,从小红书上也找到了不少的prompt,lexica.art上也有不少,主要是为了电商场景的一些测评: 小红书、civitai、Lexica、Liblib.ai、 depth o…

excel制作透视表

场景描述: 有一张excel表,存在多条记录,现在需要把相同名称的商品的数量求和,放在一起展示 操作步骤: 删除最后一行数据 选中不显示分类汇总 以表格形式展示

【算法 | 哈希表 No.2】leetcode 219. 存在重复元素II

个人主页:兜里有颗棉花糖 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 兜里有颗棉花糖 原创 收录于专栏【手撕算法系列专栏】【LeetCode】 🍔本专栏旨在提高自己算法能力的同时,记录一下自己的学习过程,希望…

黄仁勋:英伟达预言 2 年内行业将面目全非 一个词形容AI:Unbelievable

本心、输入输出、结果 文章目录 黄仁勋:英伟达预言 2 年内行业将面目全非 一个词形容AI:Unbelievable前言【访谈内容】一个词形容AI:Unbelievable创立英伟达“比想象中难一百万倍”相关图片传送门弘扬爱国精神 黄仁勋:英伟达预言 …

AR的光学原理?

AR智能眼镜的光学成像系统 AR眼镜的光学成像系统由微型显示屏和光学镜片组成,可以将其理解为智能手机的屏幕。 增强现实,从本质上说,是将设备生成的影像与现实世界进行叠加融合。这种技术基本就是通过光学镜片组件对微型显示屏幕发出的光线…

Temp directory ‘C:\WINDOWS\TEMP‘ does not exist

问题描述 解决方法 管理员权限问题,进入temp文件夹更改访问权限即可。 点击 temp文件夹 属性 -> 安全 -> 高级 -> 更改主体Users权限 给读取和写入权限 参考博客 开发springboot项目时无法启动Temp directory ‘C: \WINDOWS\TEMP‘ does not exist

Python武器库开发-常用模块之configparser模块(十六)

configparser模块(十六) ConfigParser模块在python3中修改为configparser.这个模块定义了一个ConfigParser类,该模块的作用就是用来读取配置文件的,使用模块中的RawConfigParser()、ConfigParser()、 SafeConfigParser()这三个方法,创建一个…

Github 自动化部署到GitHub Pages

1.准备工作 新建仓库 新建项目 配置 vite.config.ts base: ./,部署应用包时的基本URL,例:vue-cli 5.x 配置 publicPath 推送到远程仓库 2.配置 GitHub Token 点击 Settings -> Actions -> General 找到 Workflow permissions,选中第…

BetterDisplay Pro v1.4.15(显示器管理管理软件)

BetterDisplay Pro是一款屏幕显示优化工具,可用于Windows和Mac操作系统。它可以帮助用户调整屏幕的亮度、对比度、色彩等参数,以获得更好的视觉体验。此外,BetterDisplay Pro还提供了一些额外的功能,如屏幕分割、窗口管理、快捷键…

vivo发布“蓝心千询”自然语言对话机器人

🦉 AI新闻 🚀 vivo发布“蓝心千询”自然语言对话机器人 摘要:vivo今日发布了“蓝心千询”自然语言对话机器人,基于蓝心大模型。蓝心千询可以进行知识信息的快速问答,文学创作、图片生成,甚至还能编写程序…

✔ ★【备战实习(面经+项目+算法)】 11.3学习

✔ ★【备战实习(面经项目算法)】 坚持完成每天必做如何找到好工作1. 科学的学习方法(专注!效率!记忆!心流!)2. 每天认真完成必做项,踏实学习技术 认真完成每天必做&…

[GitLab] 安装Git 指定版本

卸载旧版本 检查是否已经安装 git --version如果已经安装,先卸载 yum -y remove git安装新版本 在GitHub上选择需要下载的版本 Git版本 在/usr/local/目录下新建文件夹:git,并在/usr/local/git/文件夹内下载压缩包 wget https://github…

串口通信代码整合1

本文为博主 日月同辉,与我共生,csdn原创首发。希望看完后能对你有所帮助,不足之处请指正!一起交流学习,共同进步! > 发布人:日月同辉,与我共生_单片机-CSDN博客 > 欢迎你为独创博主日月同…

【Redis】String字符串类型-内部编码使用场景

文章目录 内部编码使用场景缓存功能计数功能共享会话手机验证码 内部编码 字符串类型的内部编码有3种: int:8个字节(64位)的⻓整型,存储整数embstr:压缩字符串,适用于表示较短的字符串raw&…