Redis Cluster
文章目录
- 一、集群搭建
- 1 节点规划
- 2 集群启动
- 二、配置一致性
- 1 基本分工
- 2 更新规则
- 三、Sharding
- 1 数据分片
- 分片实现
- 分片特点
- 2 slot迁移
- 迁移原因
- 迁移支持
- 集群扩容
- 迁移错误
- 背景
- 现象
- 问题分析
- 验证
- 猜想
- 集群缩容
- 3. 请求路由
- client端
- server端
- migrating节点的读写
- importing节点的读写
- 关于salve节点
- 4. 迁移小结
- 四、Failover
- 1. 状态变迁
- 2. 故障发现
- 单节点感知
- 网络的不确定性
- 3. 故障确认
- 4. slave选举
- 5. 最终变更同步
- 6. Failover小结
- 总结
一、集群搭建
1 节点规划
- 计划包含多少个master/slave组;
- 每组仅存储部分数据;
- 配置文件中需要启用cluster mode;
2 集群启动
#!/bin/bash
./redis-server.sh 7380
./redis-server.sh 7381
./redis-server.sh 7382
./redis-server.sh 7383
./redis-server.sh 7384
./redis-server.sh 7385redis-cli --cluster create localhost:7380 localhost:7381 localhost:7382 localhost:7383 localhost:7384 localhost:7385 --cluster-replicas 1
二、配置一致性
1 基本分工
- 每个节点保持整个集群的所有信息;
- 每个节点持有集群信息更新版本号, 单调递增;
- 每个节点周期性地向集群中的其他节点发送心跳, PING中携带自身节点信息, PONG中携带对方所知道的集群信息;
2 更新规则
- 当某个节点率先知道了变更时,将自身的currentEpoch自增,并使之成为集群中的最大值。再用自增后的currentEpoch 作为新的Epoch版本;
- 当某个节点收到了比自己大的currentEpoch时,更新自己的currentEpoch;
- 当收到的Redis Cluster Bus 消息中的某个节点的Epoch > 自身的时,将更新自身的内容;
- 当Redis Cluster Bus 消息中,包含了自己没有的节点时,将其加入到自身的配置中。
上述的规则保证了信息的更新都是单向的,最终朝着Epoch更大的信息收敛。同时Epoch也随着currentEpoch的增加而增加,最终将各节点信息趋于稳定。
三、Sharding
1 数据分片
分片实现
- server默认整个集群有16384个slot, 然后在集群初始化时会均匀分配到每个master上, 进而可以知道每个slotId与master的对应关系。
- 由于Redis是K-V结构, 当新增某个key时, 通过算法(slotId = crc16(key) % 16384)得到slotId, 然后将目标的key写入目标slot。这里想强调的是, 由于key本身是固定的, 因此其对应的slotId也是固定的, 这是一种逻辑上的对应关系。而物理对应关系则是由配置信息中slotId与master节点的映射来实现。而这个关系对Redis client来说非常重要。
分片特点
- 解耦数据和节点之间的关系,简化了节点扩容和收缩难度。
- 节点自身维护槽的映射关系,不需要客户端 或 代理服务维护数据分片关系。
- Redis Cluster的节点之间会共享消息,每个节点都知道另外节点负责管理的槽范围。每个节点只能对自己负责的槽进行维护 和 读写操作。
虽然每个分片(shard)维护一定数量的slot, 但slot与shard的映射关系是可以动态调整的。此外, 数据迁移也是以slot为单位进行。
2 slot迁移
当sharding rebalance时, slotId与master的映射关系发生变化, slotId与key的映射关系不变。
此外, 具体的业务场景中, 考虑到数据的局部性, 可能会把相关的数据放入同一个slot上, 此时可以在key中加入{}。此时Redis server不再使用整个key, 而是仅使用{}中的内容来计算slotId。
迁移原因
- 新的master节点加入;
- 旧节点关机下线或者维护;
- 数据分布不均衡, 需要手动调整slot位置以均衡压力;
迁移支持
具体迁移过程由外部触发, Redis Cluster本身只提供了迁移过程中需要的指令支持。
- 节点迁移状态设置, 迁移前标记源/目标节点;
- key迁移的原子化命令;
- 将迁移后的配置循环广播到其他master节点;
集群扩容
- 将新节点加入集群;
cluster meet ip
- 在新节点上设置待导入的slot
cluster setslot {slotId} importing {sourceNodeId}
cluster setslot 0 importing 5df7af18093ac10b8a4a4121abb1b4fd6b0465c3
3. 数据源节点设置待迁移的slot
cluster setslot {slotId} migrating {targetNodeId}
cluster setslot 0 migrating 199a9dec48962ec0a017a28a85a5fa9b414d91f3
4. 源节点获取一批目标slot的key
cluster getkeysinslot {slotId} {count}
cluster getkeysinslot 0 100
-
从源节点发起迁移
migrate {targetNodeIp} {targetNodePort} "" 0 {timeout} keys { key... }
migrate localhost 7381 “” 0 1000 keys key-c19780 key-c13965 key-c9249
该步骤手动执行, 如果目标地址错误, 则数据丢失。仅有 -
重复4和5直到获取不到新的key
-
广播新的slot位置
cluster setslot {slotId} node {nodeId}
cluster setslot 0 node 7fc05faa8893c7f75aab12e057a40176a873e4ca
设置会让导入节点的Epoch自增,成为Cluster中的最新值,然后通过Redis Cluster Bus相互感知,传播到Cluster中的其他节点。
7. 如果是存量集群内部迁移, 则不考虑新节点加入, 其他步骤相同。
迁移错误
背景
源和目标节点状态设置正确, 但migrate的目标位置错误不是既定的目标节点;
现象
源节点slot状态为migrating;
目标节点slot状态为importing;
migrate也迁移成功,然后在不同节点的表现有点花:
- 在源节点上get返回ASK {实际migrate节点};
- 在{migrate目标节点}get返回MOVED {源节点};
- 在importing节点上get返回MOVED {源节点};
问题分析
-
数据是否丢失?
a. 从上面get的结果来看, 无法从任何一个节点中读取出来;
b. 从migrate成功来看, 数据一定在{实际migrate节点}上;
c. 在{实际migrate节点}上, 执行keys发现key是存在的, 因此可以确定数据未丢失; -
为何无法读取?
显然每个key都有对应的slot, 并且slot需要在当前的节点。因此该问题的root cause是, 数据位置和slot配置信息不一致。而目前由于value无法读取, 因此无法再对数据做移动。只能调整slot位置, 尝试通过cluster set slot设置slot的位置为当前节点。
验证
- 执行cluster slot命令到实际数据接收节点, 成功;
- 在实际数据接收节点执行get key命令, 成功;
- 在其他节点执行get key命令, 统一MOVDED到新节点;
- 至此, 问题解决;
猜想
- Redis Cluster的配置和存储之间没有强约束, 也就是虽然我当前节点没有某个slot的配置信息, 但是migrate的情况下依然可以接收目标key, 只是无法读取出来;
- 设置importing和migrating的状态, 仅是告诉client这个slot中的key有不确定性。这种不确定性由其他节点完成最终确定, 如果是人为错误, 就一直在确定的路上;
- 每个节点由于不掌握全局信息, 只能按照自己已知的信息来回复client;
- 其实slot的迁移直接可以通过cluster setslot完成, 其中的数据迁移依赖外部的处理, 至于迁移过程中client的访问结果则看server的状态;
- 总体来看, 整个过程耦合非常松散, 手动操作容易出错, 运维时得务必小心;
集群缩容
- 确认目标节点是否有负责的slot;
- 如果有负责的slot, 则需要将其迁移到其他节点上, 数据迁移过程可参考集群扩容;
- 数据迁移完毕后, 通知其他master忘记该节点;
- 当所有节点都忘记该节点后, 即可下线;
3. 请求路由
从运行时来看, slotId与master节点的映射关系是动态的。因此每次请求都要先确定映射关系, 这就是请求路由。
client端
- 连接集群中任意一个host缓存其映射关系快照;
- 后续实际访问的过程中更新本地缓存;
- 每次操作key之前先读取本地缓存确定目标实例;
server端
ask命令: 如果slot在迁移过程中, 则重定向到源节点或者目标节点确认;
moved命令: 如果slot已经移动完毕, 则返回moved;
migrating节点的读写
当某个节点的状态置为migrating后,表示对应的slot正在导出,为保证该slot数据的一致性,节点此时提供的写服务和通常状态下有所区别。
a. 对于某个迁移中的slot, 如果Client访问的key尚未迁出,则正常的处理该key;
b. 对于某个迁移中的slot, 如果key已经迁出或者key不存在,则回复Client ASK信息让其跳转到importing节点处理;
importing节点的读写
当节点状态变成importing后,表示对应的slot正在导入。此时的读写服务和通常情况下有所区别。
a. 当Client的访问不是从ask跳转的,说明Client还不知道迁移。有可能操作了尚未迁移完成的,处于源节点上面的key,如果这个key在源节点上被修改了,则后续会产生冲突。所以对于该slot上所有非ask跳转的操作, 导入节点不会进行操作,而是通过moved让Client跳转至导出节点执行。
b. 这样的状态控制,保证了同一个key在迁移之前总是在源节点执行,迁移后总是在目标节点执行, 从而杜绝了双写的冲突;
c. 迁移过程中,新增加的key会在目标节点执行,源节点不会新增key, 使得迁移key趋向于收敛, 最终在某个时刻结束。
关于salve节点
a. 单个key的迁移过程可以通过原子化的migrate命令完成;
b. 对于A/B的slave节点则通过主备复制,从而达到增删数据;
4. 迁移小结
- 关于slot迁移, 其中存量key的完整性由发起迁移的client保证, 增量key的完整性由Redis Cluster本身保证;
- 关于migrate原子性的实现, 个人YY是基于Redis单线程命令执行。当执行用户读写命令时, key存在则执行操作, key不存在则返回ask。migrate操作读取源数据, 写入目标节点, 确认成功后删除源数据的操作, 有点儿类似于同时在migrating和importing节点做操作, 结果一边删除key而另一边增加key。显然, 如果读写是并发执行的, 可能需要额外的协调机制;
四、Failover
同Sentinel 一样,Redis Cluster 也具备一套完整的故障发现、故障状态一致性保证、主备切换机制。
1. 状态变迁
- 故障发现:当某个master 宕机时,宕机时间如何被集群其他节点感知。
- 故障确认:多个节点就某个master 是否宕机如何达成一致。
- slave选举:集群确认了某个master 宕机后,如何将它的slave 升级成新的master;如果有多个slave,如何选择升级。
- 集群结构变更:成功选举成为master后,如何让整个集群知道,以更新Cluster 结构信息。
2. 故障发现
单节点感知
Redis Cluster 节点间通过Redis Cluster Bus 两两周期性的PING/PONG 交互。当某个节点宕机时,其他Node 发出的PING消息没有收到响应,并且超过一定时间(NODE_TIMEOUT)未收到,则认为该节点故障,将其置为PFAIL状态(Possible Fail)。后续通过Gossip 发出的PING/PONG消息中,这个节点的PFAIL 状态会传播到集群的其他节点。
网络的不确定性
Redis Cluster的节点两两保持TCP连接,当对PING 无反馈时,可能是节点故障,也可能是TCP链接断开。如果是TCP 断开导致的误报,虽然误报消息会因为其他节点的正常连接被忽略,但是也可以通过一定的方式减少误报。Redis Cluster 通过预重试机制排除此类误报:当 NODE_TIMEOUT/2 过去了,但是还未收到响应,则重新连接重发PING消息,如果对端正常则在很短的时间内就会有响应。同样如果是TCP连接断开, 也会对连接有效性做一次检测, 最终可以得出已确认的网络不可达。
3. 故障确认
对于网络分隔的情况,假设集群有4个节点(A,A1,B,B1),B并没有故障, 然而和B1无法连接,同时可以和A,A1可以正常联通。此时只会有B1将B标记为PFAIL状态,其他节点认为B正常,此时Redis Cluster通过故障确认协议达成一致。
集群中每个节点都是Gossip的接收者, B1也会接收到来自其他节点的GOSSIP消息,被告知B是否处于PFAIL状态。当B1收到来气其他master节点对于B的PFAIL达到一定数量后,会将B的PFAIL状态升级为FAIL状态, 表示B已经确认为故障态。后面会发起master选举流程。
4. slave选举
-
如果一个节点B有多个slave(1/2/3)都认知到B处于FAIL状态了,那么可能会同时发起竞选。当B的slave个数 >= 3时,很有可能产生多轮竞选失败。为了减少冲突的出现,优先级高的slave 更有可能发起竞选,从而提升成功的可能性。这里的优先级是slave的数据最新的程度,数据越新的(最完整的)优先级越高。
-
slave 通过向其他master发送FAILVOER_AUTH_REQUEST 消息发起竞选,master收到后回复FAILOVER_AUTH_ACK消息告知是否同意。slave 发送FAILOVER_AUTH_REQUEST 前会将currentEpoch自增,并将最新的Epoch带入到FAILOVER_AUTH_REQUEST消息中,如果自己未投过票,则回复同意,否则回复拒绝。
5. 最终变更同步
当slave 收到过半的master 同意时,会替代B成为新的master。此时会以最新的Epoch 通过PONG 消息广播自己成为master,让Cluster 的其他节点尽快的更新拓扑结构。
当B恢复可用之后,它仍然认为自己是master,但逐渐的通过Gossip 协议得知某个slave已经替代了自己,然后主动降级为新master的slave。
6. Failover小结
- 从整个过程来看, 对于一组主从, 从节点发现主节点断开, 需要借助其他节点来帮助完成故障确认。
- 最终, 也是某个slave最先将master标记为Fail。一旦完成对master的Fail标记, slave节点就会发起选举(毕竟最具条件, 时刻准备谋权篡位)。
- 在选举成功后, 原来的master也要为新master让步。
总结
本文介绍了Redis Cluster模式集群的搭建、数据分区的迁移以及故障迁移过程, 希望能帮助你对Redis Cluster模式有更进一步的认识和理解, 感谢您的阅读。
相关文章:
Redis Cluster
文章目录 一、集群搭建1 节点规划2 集群启动 二、配置一致性1 基本分工2 更新规则 三、Sharding1 数据分片分片实现分片特点 2 slot迁移迁移原因迁移支持集群扩容迁移错误背景现象问题分析验证猜想 集群缩容 3. 请求路由client端server端migrating节点的读写importing节点的读写…...

Pandas常用指令
astype astype的作用是转换数据类型,astype是没办法直接在原df上进行修改的,只能通过赋值的形式将原有的df进行覆盖,即df df.astype(dtype) astype的基本语法 DataFrame.astype(dtype, copyTrue, errorsraise) dtype参数指定将数据类型转换…...

FPGA实战小项目3
基于FPGA的波形发生器 基于FPGA的波形发生器 基于FPGA的beep音乐播放器设计 基于FPGA的beep音乐播放器设计 基于FPGA的cordic算法实现DDS sin和cosine波形的产生 基于FPGA的cordic算法实现DDS sin和cosine波形的产生...

mysql创建用户
创建用户 创建 -- 创建用户 itcast , localhost只能够在当前主机localhost访问, 密码123456; create user test01localhost identified by 123456;使用命令show databases;命令,只显示一个数据库,因为没有权限 -- 创建用户 test02, 可以在任意主机访问…...

程序员写好简历的5个关键点
程序员就业竞争大?找不到工作?也许,从简历开始你就被淘汰了.... 在很多的公司中,HR的招聘压力是很大的,浏览每个人的简历的时间可能只有20几秒,所以即使你的工作能力十分的强,但如果你没有在简…...
Vue:关于如何配置一级路由和二级路由的方法
路由的嵌套配置 文章目录 路由的嵌套配置配置一级路由 配置一级路由 创建router文件夹,里面添加index.js文件配置以下代码: import Vue from vue import VueRouter from "vue-router"; import Layout from /views/Layout import ArticleDeta…...

【论文绘图】seaborn分类数据绘图
参考:https://seaborn.pydata.org/tutorial/categorical.html 分类变量关系图中的catplot类似于连续变量中的relplot,默认是stripplot。 分类变量图种类 分类散点图 stripplotswarmplot (kind‘swarm’) 类别分布图 boxplotviolinplotboxenplot …...

KubeSphere Namespace 数据删除事故分析与解决全记录
作者:宇轩辞白,运维研发工程师,目前专注于云原生、Kubernetes、容器、Linux、运维自动化等领域。 前言 2023 年 7 月 23 日在项目上线前夕,K8s 生产环境出现故障,经过紧急修复之后,K8s 环境恢复正常&#…...
mysql场景题:最近7天连续3天登陆用户,字段,id,date(已去重)
1.最近7天连续3天登陆用户,字段,id,date(已去重) 思路: lag对时间开窗(注意时间得转换为时间戳(int类型才可以添加后续条件),跳行为2(连续3天&am…...

华为OD机试 - 最差产品奖 - 双端队列 deque(Java 2023 B卷 200分)
目录 专栏导读一、题目描述二、输入描述三、输出描述四、解题思路五、Java算法源码六、效果展示1、输入2、输出3、说明 华为OD机试 2023B卷题库疯狂收录中,刷题点这里 专栏导读 本专栏收录于《华为OD机试(JAVA)真题(A卷B卷&#…...
【校招VIP】前端算法考察之链表算法
考点介绍: 链表是一种物理存储结构上非连续的数据结构,数据的逻辑顺序是通过链表中的指针链接次序实现相互勾连。链表相对数组而言有很多不同之处,在特定场景下能发挥独特的优势。例如链表的插入和删除操作比数组效率高,数组需要改变其他元素的位置,而链表只需要改变…...

uni-app之android离线自定义基座
一 为什么要自定义基座 1,基座其实就是一个app,然后新开发的页面可以直接在手机上面显示,查看效果。 2,默认的基座就是uniapp帮我们打包好的基座app,然后我们可以进行页面的调试。 3,自定义基座主要用来…...

【AWS】实操-保护 Amazon S3 VPC 终端节点通信
文章目录 实验概览目标实验环境任务 1:探索并启动实验环境任务 1.1:探索 Amazon VPC 资源任务 1.2:探索 Amazon EC2 资源任务 1.3:创建 Amazon VPC 终端节点任务 1.4:连接私有 EC2 实例任务 1.5:探索 Amazo…...

C# Color颜色RGB对照表
序号Color色系颜色RGB图例1Color.AliceBlue蓝色艾丽丝蓝240,248,2552Color.AntiqueWhite白色古典白色250,235,2153Color.Aqua,Color.Cyan青色浅蓝色,蓝绿色,青色0,255,255 C# Color颜色RGB对照表_旭东怪的博客-CSDN博客 C#颜色和名称样式对照…...
Thread中几个常用的api详解join,interrupt
1.join() join方法可以在多线程中帮我们实现调用线程的同步效果,比如,现在有三个线程,a,b,c a中启动了b和c线程异步去执行一件事,但是a希望他们做完以后再继续往下执行,那么就可以在调用b和c启…...
Golang项目实战(三)
Golang项目实战(三) 该项目是使用grpcgin来构建的一个电商微服务项目,使用consul来注册和发现微服务。 项目简介创建项目架构创建货币服务创建货币微服务处理器将货币微服务注册到consul下载安装consul并发布服务创建商品微服务准备商品数据…...

TSUMU58CDT9-1显示器芯片方案
TSUMU58CDT9-1是用于LCD显示器的整体解决方案图形处理IC,面板分辨率高达WUXGA。它配置了高速集成三adc /PLL、集成DVI/HDMI接收器、高质量显示处理引擎、集成微控制器和支持LVDS面板接口格式的输出显示接口。TSUMU58CDT9-1支持一个灵活的可配置数字输入接口…...
React 安装使用 Less(详细流程,包含 webpack、craco 方式)
一、简介 React 项目开发中可能会使用到 Less、Sass 等样式预处理器,create-react-app 创建的 React 项目,默认就是支持 Sass 的。如果需要使用 Less 则需要额外手动安装配置。 二、方式一:webpack.config.js 配置(不推荐&#…...
力扣(LeetCode)算法_C++—— 快乐数
编写一个算法来判断一个数 n 是不是快乐数。 「快乐数」 定义为: 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。 如果这个过程 结果为 1࿰…...
滴滴笔试——算式转移
题目:给出一个仅包含加减乘除四种运算符的算式(不含括号),如12*3/4,在保持运算符顺序不变的情况下,现在你可以进行若干次如下操作:如果交换相邻的两个数,表达式值不变,那么你就可以交换这两个数…...

iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘
美国西海岸的夏天,再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至,这不仅是开发者的盛宴,更是全球数亿苹果用户翘首以盼的科技春晚。今年,苹果依旧为我们带来了全家桶式的系统更新,包括 iOS 26、iPadOS 26…...

《通信之道——从微积分到 5G》读书总结
第1章 绪 论 1.1 这是一本什么样的书 通信技术,说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号(调制) 把信息从信号中抽取出来&am…...

新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案
随着新能源汽车的快速普及,充电桩作为核心配套设施,其安全性与可靠性备受关注。然而,在高温、高负荷运行环境下,充电桩的散热问题与消防安全隐患日益凸显,成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...

前端开发面试题总结-JavaScript篇(一)
文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包(Closure)?闭包有什么应用场景和潜在问题?2.解释 JavaScript 的作用域链(Scope Chain) 二、原型与继承3.原型链是什么?如何实现继承&a…...

SpringCloudGateway 自定义局部过滤器
场景: 将所有请求转化为同一路径请求(方便穿网配置)在请求头内标识原来路径,然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...

安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖
在Vuzix M400 AR智能眼镜的助力下,卢森堡罗伯特舒曼医院(the Robert Schuman Hospitals, HRS)凭借在无菌制剂生产流程中引入增强现实技术(AR)创新项目,荣获了2024年6月7日由卢森堡医院药剂师协会࿰…...

RSS 2025|从说明书学习复杂机器人操作任务:NUS邵林团队提出全新机器人装配技能学习框架Manual2Skill
视觉语言模型(Vision-Language Models, VLMs),为真实环境中的机器人操作任务提供了极具潜力的解决方案。 尽管 VLMs 取得了显著进展,机器人仍难以胜任复杂的长时程任务(如家具装配),主要受限于人…...

c++第七天 继承与派生2
这一篇文章主要内容是 派生类构造函数与析构函数 在派生类中重写基类成员 以及多继承 第一部分:派生类构造函数与析构函数 当创建一个派生类对象时,基类成员是如何初始化的? 1.当派生类对象创建的时候,基类成员的初始化顺序 …...
掌握 HTTP 请求:理解 cURL GET 语法
cURL 是一个强大的命令行工具,用于发送 HTTP 请求和与 Web 服务器交互。在 Web 开发和测试中,cURL 经常用于发送 GET 请求来获取服务器资源。本文将详细介绍 cURL GET 请求的语法和使用方法。 一、cURL 基本概念 cURL 是 "Client URL" 的缩写…...

通过 Ansible 在 Windows 2022 上安装 IIS Web 服务器
拓扑结构 这是一个用于通过 Ansible 部署 IIS Web 服务器的实验室拓扑。 前提条件: 在被管理的节点上安装WinRm 准备一张自签名的证书 开放防火墙入站tcp 5985 5986端口 准备自签名证书 PS C:\Users\azureuser> $cert New-SelfSignedCertificate -DnsName &…...