Redis第8讲——Cluster集群模式详解

前面两篇文章介绍了Redis主从和哨兵模式,不难发现,它们都有一些共同的缺点,首先在主从切换的过程中会丢失数据;另一个就是只有一个master,只能单点写,并没有水平扩容能力。而且每个节点都保存了所有的数据,这使得内存占用率变高,另一个就是如果进行数据恢复也比较慢。为了解决这些问题,集群模式应运而生,下面我们来一起看看。

一、什么是Redis Cluster

1.1 概念

Redis Cluster 是 Redis 数据库的一种集群方案,用于实现高可用性和横向扩展。Redis Cluster 将数据分布在多个节点上,每个节点负责存储部分数据,同时提供数据复制和自动故障转移功能,以确保系统的可靠性和性能。

Redis Cluster 通过支持分片(sharding)和复制(replication)来实现数据在集群中的分布和备份,从而在数据量增长时能够水平扩展,并且能够容忍单个节点的故障而不影响整个系统的正常运行。

在高可用上,集群基本是直接复用哨兵模式的逻辑,并且针对水平扩展进行了优化。

1.2 特点

  • 采用去中心化的集群模式,将数据按槽分布在多个Redis节点上,集群共有16384个槽,每个节点负责处理部分槽,并使用CRC16算法来计算key所属的槽:crc16(key,keylen) & 16383
  • 所有的Redis节点彼此互联,通过PING-PONG机制来进行节点间的心跳检测。
  • 客户端与Redis节点直连,不需要中间代理层(proxy)。客户端不需要连接集群中所有的节点,只用连接集群中任意一个可用节点即可。
  • 采用主从复制机制,将数据复制到多个节点上。每个主节点会有一个或多个从节点。在实际使用中,通常会将主从分布在不同机房,避免机房出现故障导致整个分片出问题,如下图。

二、在集群中执行命令

在对16384个槽指派后,集群就会进入上线状态,当客户端向节点发送与数据库键有关的命令时,接收命令的节点会计算出命令要处理的数据库键属于哪个槽:

  • 如果刚好是当前槽,那么节点直接执行命令。
  • 反之,节点就会返回一个MOVED错误,指引客户端转向至正确的节点,并再次发送之前想要执行的命令。

2.1 计算key属于哪个槽

ps:由于篇幅原因,这个在后续的文章中会详解。

Redis 集群中内置了 16384 个哈希槽,redis 会根据节点数量大致均等的将哈希槽映射到不同的节点。当需要在 Redis 集群中放置一个 key-value时,redis先对key使用crc16算法算出一个结果,然后用结果对16384求余数[ CRC16(key) % 16384]这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,也就是映射到某个节点上。

使用CLUSTER KEYSLOT <key>命令可以查看一个key属于哪个槽,这个命令就是通过调用上面给出的槽分配算法来实现的。

2.2 MOVED错误

当节点发现key所在的槽并非是自己负责处理的时候,节点就会向客户端返回一个MOVED错误(MOVED <slot> <ip>:<port>),其中slot为key所在槽,ip和port则是负责处理槽的节点ip和端口号。

在客户端接收到节点返回的MOVED错误时,客户端会根据MOVED错误中提供的ip和端口号,转向负责处理槽的节点,并向该节点发送之前想要执行的命令。

三、 重新分片

Redis集群的重新分片操作可以将任意数量已经指派给某个节点(源节点)的槽改为指派给另一个节点(目标节点),并且相关槽所属的键值对也会从源节点被移动到目标节点,该过程可以在线(online)进行。

Redis集群的重新分片操作是由Redis的集群管理软件redis-trib负责执行的,步骤如下:

  • redis-trib对目标节点发送CLUSTER SETSLOT<slot>IMPORTING<source_id>命令,让目标节点准备好从源节点导入(import)属于槽slot的键值对。
  • redis-trib对源节点发送CLUSTER SETSLOT<slot>MIGRATING<target_id>命令,让源节点准备好将属于槽slot的键值对迁移(migrate)至目标节点。
  • redis-trib向源节点发送CLUSTER GETKEYSINSLOT<slot><count>命令,获得最多count个属于槽slot的键值对的键名(key name)。
  • 对于步骤3获得的每个键名,redis-trib都向源节点发送一个MIGRATE<target_ip><target_port><key_name>0<timeout>命令,将被选中的键原子地从源节点迁移至目标节点。
  • 重复执行步骤3和步骤4,直到源节点保存的所有属于槽slot的键值对都被迁移至目标节点为止。
  • redis-trib向集群中的任意一个节点发送CLUSTER SETSLOT<slot>NODE<target_id>命令,将槽slot指派给目标节点,这一指派信息会通过消息发送至整个集群,最终集群中的所有节点都会知道槽slot已经指派给了目标节点。

四、ASK错误

在进行重新分片期间,源节点向目标节点迁移一个槽的过程中,可能会出现这样一种情况:属于被迁移槽的一部分键值对保存在源节点里面,而另一部分键值对则保存在目标节点里面。

当客户端向源节点发送一个与数据库键有关的命令,并且命令要处理的数据库键恰好就属于正在被迁移的槽时。源节点会先在自己的数据库里面査找指定的键,如果找到的话,就直接执行客户端发送的命令。

否则,这个键有可能已经被迁移到了目标节点,源节点将向客户端返回一个 ASK 错误,指引客户端转向正在导入槽的目标节点,并再次发送之前想要执行的命令,从而获取到结果。

五、MOVED和ASK的区别

从上面看,MOVED和ASK都启到了重定向客户端的效果,那么它们有什么区别呢,简单的说就是:

  • MOVED代表该槽已经完全由另一个节点负责了,会触发客户端刷新本地路由表,之后对于该槽的请求都会请求新的节点。
  • ASK只是在槽迁移中的一种临时措施,只是会产生一次重定向。

ps:本地路由表是该集群的插槽和负责处理该槽的节点地址的映射,通过该路由表,客户端可以在大部分情况下都直接请求到正确的节点,而无需重定向。

六、复制与故障转移

6.1 gossip协议

6.1.1 什么是gossip协议

这里先介绍一下gossip协议(下面会用到),全称Gossip protocol也叫Epidemic Protocol(流行病协议),那么它是干嘛的呢?

在整个Redis集群中,如果出现以下情况:

  • 新节点加入。
  • slot迁移。
  • 节点宕机。
  • slave选举成为master。

我们希望这些变化能够让整个集群的每个节点能够尽快发现,那么各个节点之间就需要相互连通并且携带相关状态数据进行传播,这就用到了gossip协议。

你可能会想到用广播的方式不也可以实现,答案是当然可以,但是对CPU和带宽的消耗比较大,所用还是采用goosip协议。

该协议的特点是,在节点数量有限的网络中,每个节点都会“随机”(也不是真正的随机,而是根据规则选择通信节点)与部分节点通信,经过一番杂乱无章(传染病)的通信后,每个节点的状态可以在一定时间内达成一致。

6.1.2 gossip协议消息

gossip协议包含多种消息,比如ping、pong、meet、fail等

  • ping:每个节点都会频繁给其它节点发送ping,包含自己的状态还有维护的集群元数据,通过ping互相交换元数据。
  • pong:返回ping和meet,包含自己的状态和其它信息,也可以用于信息广播和更新。
  • fail:某个节点判断另一个节点fail后,就发送fail通知其它节点该节点下线了。
  • meet:当发送者接到客户端发送CLUSTER MEET命令时,发送者会向接收者发送MEET消息,请求接收者加入到发送者所在的集群里面。

6.2 复制

集群的每个分片都使用主从复制保证高可用,之前的文章中已经介绍过了,就不再赘述了。

6.3 故障检测

与哨兵模式的故障检测核心思想基本一致。

集群中的每个节点都会定期地向集群中的其它节点发送PING消息,以此来检测是否在线,发送PING消息的时机主要有两个:

  • 每秒执行一次:随机检查5个节点,选出最早收到PONG回复的节点,即最久没有通信过的节点,发送PING消息。
  • 每100毫秒执行一次:轮询集群的节点,对于正常节点,如果上次收到该节点的PONG回复的时间距离现在,已经超过集群超时时间的一半(cluster-node-timeout/2)则直接向该节点发送PING消息。

如果接收 PING 消息的节点在规定的时间内(cluster-node-timeout,默认15秒-conf配置文件),没有返回 PONG 回复或者发送其他任何消息,那么发送 PING 消息的节点就会将接收 PING 消息的节点标记为疑似下线probable failure,PFAIL)。

ps:这边 Redis 没有将 PONG 回复作为目标节点存活的唯一证明,而是将目标节点的任何消息都作为存活的证明。这是因为在集群负载较高的时候,收到 PONG 回复可能会出现延迟。

如果一个集群里面,半数以上主节点都将某个主节点x报告为疑似下线,那么该主节点x将被标记为已下线FAIL),将主节点x标记为已下线的节点会向集群广播一条关于主节点x的FAIL消息,所有收到消息的节点会立即将主节点x标记为已下线。

6.4 选举新的主节点

故障转移的第一步就是选举新的主节点,该方法和选举领头Sentinel的方法非常相似,因为两者都是基于Raft算法实现的。

6.4.1 epoch(纪元)

在介绍该流程之前我们先了解一个名词epoch(纪元):Redis集群中使用了类似Raft算法term(任期)的概念成为epoch(纪元),在Redis集群中主要有两种:

  • currentEpoch(集群配置纪元):是一个集群范围内的全局递增计数器,用于跟踪集群的状态变化。每当集群发生状态变化,如节点加入、离开、主从切换等,currentEpoch就会增加。这有助于确保集群中的各个节点都了解到最新的集群状态。例如,当一个新的节点加入集群时,它会从其他节点获取当前的 currentEpoch,以确保它了解到最新的集群状态。
  • configEpoch(节点配置纪元):是每个节点上的参数,表示节点在处理集群配置时的版本号。当一个节点成为集群中的主节点时,它的 configEpoch 会增加,并且这个增加的值会被广播给整个集群,以通知其他节点。这个值在 Redis 集群中被用来判断一个节点是否已经接受了来自其他节点的新的配置。如果一个节点的 configEpoch 落后于其他节点,则说明它需要更新配置以保持与集群的一致性。这对于确保集群的配置是一致的非常重要,特别是在故障恢复、主从切换等情况下。

6.4.2 流程

  • 当从节点发现自己正在复制的主节点进入已下线状态时,会发起一次选举:将 currentEpoch 加1,然后向集群广播一条 CLUSTERMSG_TYPE_FAILOVER_AUTH_REQUEST 消息,要求所有收到这条消息、并且具有投票权的主节点向这个从节点投票。

  • 其它节点收到消息后,会判断是否要给发消息的节点投票:

    • 当前节点是slave或master,但不负责处理槽,则当前节点没有投票权,直接返回。

    • 请求节点的currentEpoch小于当前节点,校验失败。因为发送者的状态与当前集群不一致,可能是长时间下线的节点刚刚上线,直接返回。

    • 当前节点已经投过票了,检验失败。

    • 请求节点是master或为空,检验失败。

    • 请求节点的master没有故障,并且不是手动故障转移,检验失败。

    • 上一次为该master投票时间在cluster-node-timeout的2倍范围之内,检验失败。这个用于使获胜从节点有时间将其成为新主节点的消息通知给其他从节点,从而避免另一个从节点发起新一轮选举又进行一次没必要的故障转移。

    • 请求节点的configEpoch如果比之前负责这些槽位的节点小,检验失败。

  • 通过以上校验,主节点才会向要求投票的从节点返回一条CLUSTERMSG_TYPE_FAILOVER_AUTH_ACK消息,从节点会根据收到这个消息的条数来统计获得了多少个主节点的支持(票数)。

  • 当一个从节点收集到N/2+1张票支持(N代表具有投票权的主节点)时,这个从节点就会当选为新的主节点。(每个主节点只能投一次票)

  • 如果在一个配置纪元内所有从节点都没能收到足够的票,那么集群会开启新的纪元,再次选举,直到选出为止。

6.5 故障转移

当slave发现自己正在复制的master处于已下线(FAIL)状态时,slave会对下线的matser进行故障转移:

  • 发起一次选举,该下线的master的所有slave里面,会有一个slave被选中。
  • 被选中的slave会执行SLAVEOF no one命令,成为新的master。
  • 新的master会撤销所有对已下线master的槽指派,并将这些槽全部指向自己。
  • 新的master向集群广播一条PONG消息,这条PONG消息可以让集群中的其它节点立即知道这个节点已经“上位”了,并且已经接管了原本由已下线节点负责处理的槽。集群中的其他节点收到消息后会更新自己保存的相关配置信息。
  • 新的master开始接收和自己负责处理的槽相关的命令请求,至此,故障转移完成。

七、优缺点

优点:

  • Redis Cluster 采用分布式架构,自动将数据分片存储在多个节点上,提供了良好的横向扩展性和高可用性。
  • 集群节点可以自动发现和重新分片,并且支持节点动态扩容和缩减,减少了集群管理的复杂性。
  • 当新的节点加入或离开集群时,Redis Cluster 能够自动进行节点发现和重新分片,而无需手动干预,这简化了集群管理的复杂度。

缺点:

  • Redis Cluster 不支持跨分片的事务操作,事务必须在同一分片上执行,这可能会在某些场景下带来限制。
  • 配置和管理 Redis Cluster 相对复杂,需要理解分布式系统的原理和网络分区等问题。需要投入更多的精力来实施和维护集群。

End:希望对大家有所帮助,如果有纰漏或者更好的想法,请您一定不要吝啬你的赐教🙋。  

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

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

相关文章

sqlite3——数据库——day2

今天学习了sqlite3数据库 sqlite3_open sqlite3_openint sqlite3_open(const char *filename, /* Database filename (UTF-8) */sqlite3 **ppDb /* OUT: SQLite db handle */); 功能:打开数据库文件(创建一个数据库连接) 参数:filename:数据库文件路径 ppDb:操作数…

Python使用lxml解析XML格式化数据

Python使用lxml解析XML格式化数据 1. 效果图2. 源代码参考 方法一&#xff1a;无脑读取文件&#xff0c;遇到有关键词的行再去解析获取值 方法二&#xff1a;利用lxml等库&#xff0c;解析格式化数据&#xff0c;批量获取标签及其值 这篇博客介绍第2种办法&#xff0c;以菜鸟教…

如何实现Git Push之后自动部署到服务器?

在平时个人开发的过程中是不是有这样的烦恼&#xff1a; 项目开发完成&#xff0c;Push之后 登录服务器&#xff0c;手动git pull&#xff0c;然后运行部署命令 这真的很烦诶&#xff01; 那么能不能Git push之后&#xff0c;远端服务器自动 Git pull 然后运行部署命令呢&a…

信息系统项目管理师002:信息系统(1信息化发展—1.1信息与信息化—1.1.2 信息系统)

文章目录 1.1.2 信息系统1.信息系统及其特性2.信息系统生命周期 记忆要点总结 1.1.2 信息系统 信息系统是由相互联系、相互依赖、相互作用的事物或过程组成的具有整体功能和综合行为的统一体。在经济与社会活动中&#xff0c;经常使用“系统”的概念&#xff0c;例如&#xff0…

python的函数与类的定义

目录 1.函数 1.函数的定义 2.输入参数与输出参数的类型 3.输入和输出多个参数 1.普通参数 2.含有任意数量的参数 3.关键字参数 4.普通参数与多个参数的结合 2.类 1.类的定义 2.类的实例化 3.继承 1.函数 1.函数的定义 def 函数名(输入参数): 文档字符串 函数体 …

Ubuntu20下C/C++编程开启TCP KeepAlive

1、在linux下&#xff0c;测试tcp保活&#xff0c;可以使用tcp自带keepalive功能。 2、几个重要参数&#xff1a; tcp_keepalive_time&#xff1a;对端在指定时间内没有数据传输&#xff0c;则向对端发送一个keepalive packet&#xff0c;单位&#xff1a;秒 tcp_keep…

HTML静态网页成品作业(HTML+CSS+JS)——体育足球介绍设计制作(3个页面)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;使用Javacsript代码实现图片轮播&#xff0c;共有3个页面。 二、作品…

借助ChatGPT提高编程效率指南

PS: ChatGPT无限次数&#xff0c;无需魔法&#xff0c;登录即可使用,网页打开下面 一、借助ChatGPT提高编程效率指南 随着计算机技术的飞速发展&#xff0c;编程已经成为了现代社会中一个非常重要的技能。对于许多人来说&#xff0c;编程不仅是一项工作技能&#xff0c;而且是…

HCIP —— BGP 路径属性 (上)

目录 BGP 路径属性 1.优选Preferred-Value属性值最大的路由 2.优选Local-preference 属性数值大的路由 3.本地始发的BGP路由优先于其他对等体处学习到的路由。 4..优选AS_PATH属性值最短的路由 BGP 路径属性 BGP的路由选路是存在优选规则的&#xff0c;下图为华为官网提供…

【MySQL探索之旅】MySQL数据表的增删查改(初阶)

&#x1f4da;博客主页&#xff1a;爱敲代码的小杨. ✨专栏&#xff1a;《Java SE语法》 | 《数据结构与算法》 | 《C生万物》 |《MySQL探索之旅》 ❤️感谢大家点赞&#x1f44d;&#x1f3fb;收藏⭐评论✍&#x1f3fb;&#xff0c;您的三连就是我持续更新的动力❤️ &…

Mac使用自动操作(Automator)发送文件到Android设备

需求场景 在Android开发调试的过程中&#xff0c;当需要把电脑上的文件传输到连接的Android设备时&#xff0c;通常的做法是通过adb push命令。那既然是通过命令操作&#xff0c;是否可以通过可视化的工具来操作呢&#xff1f;例如在Finder中&#xff0c;右击某一个文件或者目…

上海亚商投顾:沪指缩量调整 传媒、游戏股逆势大涨

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 一.市场情绪 三大指数昨日震荡调整&#xff0c;上证50指数跌近1%&#xff0c;保险等权重板块走低&#xff0c;中国太保跌超…

【Java/Image】给指定路径下图片反色并加上当前日期形式的水印

【需求】 从通达信软件截屏下来的K线图&#xff0c;在打印前需要反色&#xff0c;打印后需要手动加上当前日期&#xff0c;这些都可以由程序代替手工完成。 以下是期待的效果。 【关键点】 给图片反色用的是梯度法&#xff0c;这个在网络上已有成型代码&#xff1b; 给图片…

职场中的“刺猬”与“狐狸”:如何找到你的竞争优势?

职场如战场&#xff0c;竞争激烈。每个人都试图找到自己的竞争优势&#xff0c;以在职场中脱颖而出。在寻找竞争优势的过程中&#xff0c;我们可以从"刺猬"和"狐狸"的角度来思考。那么&#xff0c;什么是"刺猬"和"狐狸"呢&#xff1f;…

《汇编语言》- 读书笔记 - 第17章-外传之 DOSBox-X 调用 int 13 读写磁盘

《汇编语言》- 读书笔记 - 第17章-外传之 DOSBox-X 调用 int 13 读写磁盘 总结dosbox-x.conf 不完美读取成功写入成功参考资料 总结 DOSBox 中访问 int 13h 始终没反应。网上查了下有人说是没支持&#xff0c;建议使用 DOSBox-X 经过无数遍尝试后&#xff1a; 环境状态Win11…

构建社区服务平台的智慧架构

社区服务平台作为连接社区居民与各类服务资源的桥梁&#xff0c;承载着提升居民生活品质、促进社区发展的重要使命。本文将深入探讨社区服务平台的架构设计理念、核心功能和发展前景&#xff0c;助力读者了解如何构建智慧化、便捷化的社区服务平台&#xff0c;为社区居民提供更…

【Java设计模式】二十、迭代器模式

文章目录 1、迭代器模式2、案例3、总结4、在源码中的实际应用 1、迭代器模式 提供了一种遍历的方式提供了一个对象来顺序访问聚合对象&#xff08;集合、容器&#xff09;中的一系列数据&#xff0c;而不会暴露聚合对象的内部表示 相关角色&#xff1a; 抽象聚合&#xff1a…

厚膜高压电阻器应用

EAK高压厚膜电阻器可用于广泛的应用。其中包括电源、配电系统、ESD 保护、电子显微镜、空气电离设备、雷达设备、X 射线发生器和 ATE。 示例电路包括高压泄放器、电压平衡、电压调节和分压器。在这篇文章中&#xff0c;我们将讨论选择电阻器时要考虑的关键问题。 电压泄放电路…

IDEA开启Run Dashboard

1、Run Dashboard是什么&#xff0c;为什么要使用 Run Dashboard 是 IntelliJ IDEA 中的一个工具窗口&#xff0c;用于管理和监视项目中正在运行的应用程序和配置。它提供了一种集中管理运行和调试过程的方式&#xff0c;可以让开发人员更方便地查看和控制正在运行的应用程序。…

CSAPP Malloc lab

CSAPP Malloc Lab 目标 实现一个简单的动态存储分配器。 评分标准 空间利用率应当减少internal 和 external fragmentation. memory utilization memory utilization payload / heap size fragmentation internal fragmentation external fragmentation throughput T 越接…