Redis集群操作
如果有空格
如果没有空格,直接删除
(5)学习使用redis-trib命令:添加两个节点docker-compose.yaml
1 创建:创建集群环境 host1:port1 hostN:portN (集群主从节点数量) 2 调用:redis 命令 3add-node 你可以这样做:添加到集群节点,第一个参数是新的ip:端口。
节点中,第二个参数是包之一。
现有节点的IP:port4del-node[host:portnode_id]:删除节点5reshard:重新分片6check[hosts:port]:检查集群状态
第1步:使用add-nod e命令:green new为节点,红色为已知现有节点
结果如下:
第二步:检查集群状态:
注意:节点添加成功后,由于还没有分配哈希槽,所以新添加的节点将没有数据。
我们必须手动为新节点分配插槽。
第一步:使用redis-trib命令找到集群中的master节点(红色区域代表集群中的master节点)并再次复制。
结果如下:
1 提示1:新节点你想要去多少个地方? 2 技巧二:需要将这 200 个槽转移到该节点(需要指定节点 ID),下一个问题是输入 all 以提取所有主节点的响应槽数(700170027003)(总共 200 个槽)指定的新节点!,会打印分片执行计划。
) 3 提示3:确保分片功能执行 输入是。
最后我们再次扫描集群状态:
如上图所示,我们的7007现在有了一个slot,这意味着我们可以向7007读写数据了! 至此,我们的7007已经添加到集群中,并且是master节点。
第一步:我们还需要执行add-node命令
如图。
,它仍然是一个主节点,没有分配任何槽位。
第二步:我们需要执行迭代命令来识别当前节点(从节点)的主节点ID。
首先需要登录新添加的7008节点客户端,然后登录集群使用命令将当前7008(从)节点分配为主节点(这里使用之前创建的7007主节点,红色显示节点ID)
我们继续查看集群当前状态如下图: 7008我们已经成功放到了master节点7007下。
至此成功slave节点 我们增加了。
(9) 我们可以这样做来检查集群是否可以读写(当然可以)。
(10)现在我们来尝试删除一个节点(7008slave)第一步:删除从节点7008,输入delete-node命令,输入要删除的节点的ip和端口以及节点ID(红色为该节点的ID) 7008节点)
结果如下:
第2步:重新检查集群状态,当前 节点服务进程也将消失。
可以使用ps命令查看当前服务(ps -el|grepre dis),发现少了一台服务器在运行,就是现在移除的7008从节点。
在其他主节点中,再删除该节点,否则会发生数据丢失。
第一步:在删除7007(主)节点之前,我们需要将所有数据(槽)移动到其他节点(目前只能将主数据移动到一个节点,时间平均无法执行分配功能)。
结果如下:-
至此我们已经成功将7007主节点的数据迁移到7001上,我们可以看到集群当前的状态如下图。
你会发现7007下没有数据(槽)槽,这就证明迁移成功了!
结果如下:
最后,我们检查集群的状态,一切都回到了原来的状态! 好结束!
Redis集群详述(从服务内部讲解,彻底搞懂Redis集群)
1.简介Redis集群是Redis提供的分布式数据库解决方案。
集群通过分区来共享数据,Redis集群主要实现以下目标:
即使有1000个节点,它仍然具有良好的性能和扩展性。
以书面形式。
没有合并(多个节点没有相同的key),因此在Redis数据模型中最常见的大数据值中也能很好的工作。
写入安全,系统尝试保存连接到大多数节点的客户端执行的所有写入操作。
但是Redis并不能保证数据永远不会丢失,异步和同步复制无论如何都会导致数据丢失。
可用性,如果主节点不可用,从节点可以替代主节点。
关于学习Redis集群,如果你没有任何经验,建议阅读这三篇文章(中文系列):
Redis集群教程
https://redis.cn/topics/cluster-tutorial.html
Redis集群规范
https://redis.cn/topics/cluster-spec.html
部署一个假的Redis3主集群 3https://blog.csdn.net/qq_41125219/post/details/118686281
以下根据图中三主三从的结构如下:
资源列表:
IP槽位范围(slot) 对于节点[0]192.168.211.107:6319Slots0-5460Master[1]192.168.211.107:6329Slots5461-10922Master[2]192.168.211.107:6339Slots10923-16 383从机[0]192.168.211.107:6369从机[1]192.168.211.107:6349从机[2]192.168.211。107:6359
Redis集群没有使用一致性哈希,而是引入了哈希槽的概念。
Redis 集群有 16384 个哈希槽,每个键都通过 CRC16 进行扫描,并取模 16384 来确定放置哪个槽。
这种结构使得添加或删除节点变得容易。
集群中的每个节点负责一部分哈希槽。
例如上面资源列表中的集群有3个节点,槽位分配如下:
主节点[0]有一个hash。
槽位0到5460
主节点[1]包含哈希槽5461到10922
主节点[2]包含哈希槽10923到16383。
主节点[2]包含哈希槽10923到16383。
在深入了解Redis集群之前,您需要了解集群中Redis实例的内部结构。
当Redis服务节点通过配置cluster_enabled为Yes开启集群模式时,Redis服务节点不仅会继续以独立模式使用服务器组件,还会添加custerState、clusterNode、custerLink等结构体来存储集群私有数据模式。
请务必阅读下面三个对象仔细保存数据,尤其是结构体中的注释,读完后你就会了解集群一般是如何工作的。
2.1clsuterNode
clsuterNode 是用来存储节点的。
信息,如节点名称、IP地址、端口信息、配置时代等。
下面的代码列出了一些非常重要的属性:
red IS_NODE_SLAVE (从节点) // 状态 -> 在线或离线 示例:REDIS_NODE_PFAIL (疑似离线) REDIS_NODE_FAIL (离线) intflags; //节点配置epoch,用于故障转移,在sentinel中使用类似 //clusterState 表示集群的配置epoch unit64_tconfigEpoch;//节点IP地址 charip[REDIS_IP_STR_LEN];//节点端口 intport;//绑定节点集群information rLink*link ;// 2048字节二进制位数组 // 位数组的索引值可以是0或1 // 索引位置值 数组i为0,表示该节点不负责处理槽i //数组索引位置值为1,代表节点负责处理槽iunsignedcharslots[163 84/8];//记录当前节点的处理槽总数 intnumslots;//如果当前节点是从节点 //指向当前从节点的主节点 structclusterNode*slaveof;//如果是从节点 current是master节点 //复制slave到当前master节点的节点数 intnumslaves; // 数组——记录与当前主节点重复的所有子节点 structclusterNode**slaves;}clsuterNode;
上面代码中可能不太好理解的是slots[16384/8]其实也可以简单理解为一个数组大小16384。
如果数组索引下标为1,则表示当前槽属于当前块。
如果为0,则表示不属于当前blockNode。
clusterNode可以通过slot来识别当前节点负责处理哪些slot。
组中没有分配槽位的主 clsuterNode 或 clsuterNode 槽位如下:
假设该组正如上面我提供的资源列表中提到的,代表Master[0]的集群槽位如下:
clusterLink为中的一个属性 clsuterNode,用于存储连接节点所需的相关信息,例如套接字描述符、输入输出缓冲区等 下面的代码列出了一些非常重要的属性:
typedefstructclusterState{//连接创建时间mstime_tctime; // TCP 套接字描述符 intfd; // 输出缓冲区,需要发送给其他节点的消息都存放在这里 sdssndbuf; 连接到当前clsuterNode节点代表的节点,这里保存 structcluster Node*node;}clusterState;2.3custerState每个节点都会有一个custerState结构体,里面存储了当前集群的所有数据,比如集群的状态cluster,以及集群中节点的所有信息(主节点,子节点)等。
等等,下面的代码列出了一些非常重要的属性:
custerState中有3个结构体需要仔细理解,第一个是slot数组 ClustState 集群中不同 clsuterNode 中的 slot 数组 rNode 中的 slot 数组记录了当前集群负责哪些 slot,而 clusterState 中的 slot 数组则记录了该 clsuterNode 负责整个集群中每个 slot 的哪个 slot,所以,当集群运行正常,记录了每个索引。
ClustState中的slot数组表示该blockNode负责的slot。
在分配块槽之前,块将槽指示为空。
如图所示,资源列表中显示了clusterState中的slot数组和clsuterNode中的slot数组:
当我们需要获取集群负责的槽时,我们只需要查询槽数组即可在集群的状态下。
如果没有ClusterState槽数组,则需要遍历所有ClusterNode结构,速度明显较慢
此外,ClusterNode中的槽数组也是必须的,因为集群中的任何节点都需要知道彼此的负责Slot,此时节点之间只需要将集群节点中的slot、数组结构互相传递即可。
第二个必须仔细理解的结构是节点字典。
虽然结构简单,但所有集群节点都存储在节点字典中。
这也是Redis集群中的一个节点获取其他主节点信息的方式,而从节点就是master,所以我们也需要注意。
第三个必须仔细理解的结构是 importing_slots_from[16384] 数组,这两个数组在重新分区集合时必须使用 migating_slots_to[16384] ,我们稍后会讲到。
Redis集群总共有16384个槽位,如上面的资源列表所示,我们是三主三从的集群,但是,在上面的三主三从的部署过程中,我并没有看到,选择对应的master节点的slot,这是因为Redis集群本身已经给我们分区了slot,但是如果我们想自己分配slot,我们该如何修改呢?
我们可以向节点发送以下命令,为当前节点分配一个或多个槽:
CLUSTERADDSLOTS
比如我们要分配槽0和1分配给Master节点[0]时,我们只需要向Master节点[0]发送以下命令:
CLUSTERADDSLOTS 01
当一个slot分配给Master节点[0]时节点,私有槽数组将被更新 和 clusterNode. 节点会将自己负责处理的槽位,即槽位数组,通过消息发送给集群中的其他节点,其他节点会收到该消息。
当收到消息时,clusterNode对应的slots数组和clusterState的solts数组都会被更新。
这个其实比较简单。
当我们向Redis集群中的某个节点发送CLUSTERADDSLOTS命令时,当前节点首先会通过ClustState中的slot数组确认分配给当前节点的slot是否还没有分配给其他节点。
如果设置的话,会直接抛出异常,并向设置的客户端返回错误。
如果分配给当前节点的所有时隙未分配给其他节点,则当前节点将这些时隙分配给自身。
定制主要分为三个步骤:
更新clusterState的slot数组,将指定的slot[i]指向当前集群节点
更新集群节点的槽数组并设置值在指定槽slots[i]中更新为1
发送向集群中的其他节点发送消息,并将 clusterNode 的槽数组发送到其他节点。
集群中的多个节点和客户端 客户端如何知道要请求哪个节点?
在理解这个问题之前,你首先要知道一点。
Redis集群如何计算当前key属于哪个slot? 根据官网介绍,Redis实际上并没有使用一致性哈希算法,而是通过CRC16扫描每个所需的key,然后对16384进行模16384来确定放入哪个槽。
HASH_SLOT=CRC16(key)mod16384
此时,当客户端连接向某个节点发送请求时,当前接收命令的节点会首先通过计算当前的key该算法在计算出自己所属的槽位i后,当前节点会判断该块状态的槽位i是否是自己负责的,如果是的话,当前节点就会响应客户端的请求。
如果它不负责当前节点,它将经历以下过程: 后续步骤:
节点向客户端返回 MOVED 重定向错误 在 MOVED 重定向错误中,计算出的 IP 地址和 IP 地址。
处理切换的集群节点的端口会正确返回给客户端
客户端收到节点返回的MOVED转发错误后,会根据IP将命令转发到正确的节点。
地址和端口。
整个过程对程序员来说是透明的,由Redis集群服务器和客户端共同负责完成。
这个问题其实涵盖了很多问题,比如删除Redis集群中的某些节点、添加节点等。
可以概括为将哈希槽从一个节点移动到另一个节点。
Redis集群的伟大之处在于它支持在线定制(不停机),官方说是集群的livereconfiguration。
在执行之前,我们先看一下CLUSTER指令。
了解了该指令后,就可以运行它了:
CLUSTERADDSLOTSslot1[slot2] [slotN ]<。
/p>
CLUSTERDELSLOTSslot1 [slot2]…[slotN]
CLUSTERSETSLOTslotNODEnode
CLUSTERSETSLOTslotMIGRATINGnode
CLUSTERSETSLOTslotIMPORTINGnode
包括槽的 CLUSTER 指令作业 基本上就是上面的。
ADDSLOTS和DELSLOTS主要用于热分配,而槽位的热删除仅在热分配时使用。
CLUSTERSETSLOTslotNODEnode也用于直接将slot分配给指定节点。
如果创建了集合,我们通常使用最后两个来重新分配,其含义如下:
当设置时MIGRATING 上,原来拥有该哈希槽的节点仍会接受对该哈希槽的所有请求,但只有当查询的 key 仍然存在于父节点上时,父节点才会处理该请求,否则该查询将被转发到通过-ASK重定向迁移目标节点。
当某个槽设置为导入时,节点只有收到ask命令后才会接受该哈希槽的所有查询请求。
如果客户端从不发送 ASKING 命令,则查询将通过 -MOVED 转发错误重定向到实际处理此哈希槽的节点。
你是不是觉得上面两句话很难理解? 这是官方的描述。
如果你不明白,我给你一个通用的描述整个过程:Redis-trib(redis-trib集群管理软件会负责给Redis集群分配slot),发送CLUSTERSETSLOTslotIMPORTINGnode命令到目标节点(槽导入节点),它会从源节点(槽的导出节点)导入目标节点为槽做准备。
然后redis-trib向源节点发送CLUSTERSETSLOTslotslotMIGRATINGnode命令,源节点将做好导出槽的准备
然后redis-trib向源节点发送CLUSTERGETKEYSINSLOTslotc unt命令,源节点收到命令后会返回该槽的子键,并返回最大键数
redis-trib会发送命令 依次向源节点迁移ipportkey0timeout 根据源节点返回的key,如果该key存在于源节点的节点中,则会迁移到目标节点。
迁移完成后,redis-trib会通过消息槽分配信息向集群中的某个节点发送CLUSTERSETSLOTslotNODEnode命令,从而完成集群的槽迁移过程,并且集群中的其他节点使用新的时隙分配信息更新集群。
你是特别的,在这种同步的情况下你总是会想,你很棒! 大佬们!
这个问题也已被正式考虑。
还记得我们讨论过群体状态结构吗? importing_slots_from 和 migrating_slots_to 就是用来处理这个问题的。
当节点导出一个slot时,clusterState中migrating_slots_to数组对应的下标会被设置为指向对应的集群节点,这个集群节点就会指向到导入节点。
当节点导入槽时,集群状态中会设置importing_slots_from数组对应的下标指向对应的集群节点,该节点将指向导出节点。
利用上面两个倒数矩阵,我们可以判断当前slot是否正在迁移,从哪里迁移,迁移到哪里? 是不是很有趣,就这么简单
此时,我们回到问题,客户端请求的密钥是否属于正在中继的槽。
然后接收命令的节点将首先尝试在其数据库中查找密钥。
如果槽位还没有迁移,并且当前交换机还没有迁移,则可以直接响应客户端的请求。
如果key不再存在,节点会查询migration_slots_to数组对应的索引槽。
如果索引中的值不为空,而是引用了集群节点结构,则说明该键已迁移到该集群节点。
此时节点不会继续处理该指令,而是返回ASKING命令。
该命令还将具有与导入槽的 clusterNode 对应的 IP 地址和端口。
客户端收到ASKING命令后,需要将请求转发到正确的节点,但是这里有一点需要注意(所以我在这里放了一个表情符号,以供读者注意)。
前面提到,当节点发现当前槽不属于自己处理时,会返回一条MOVED指令,所以节点迁移时如何处理槽位? 这就是这个Redis集群的目的。
当节点检测到槽位正在迁移时,会向客户端返回ASKING命令。
客户端会收到一条ASKING命令,命令中包含了迁移槽位所在集群节点的IP地址和端口。
然后客户端主页将向迁移节点发送ASKING命令。
这个命令的目的应该是告诉当前节点,你要对这个请求破例,因为这个槽已经迁移给你了,你不能直接拒绝我(因此,如果没有从Redis收到ASKING命令,会直接查询到节点数组rState,而正在迁移到clusterState的slot还没有更新,只能直接返回MOVED,这样会继续迭代很多次 ),然后就需要发送下次提前再次询问命令)。
Redis集群故障比较简单,这个其实和Sentinel中的方法类似,主节点宕机或者在指定的最大时间内没有响应,创建新的主节点。
重新选举出子节点。
当然,前提是对于Redis集群中的每个主节点,我们都提前设置好了从节点,否则就没用了……大致步骤如下:
在集群正常运行时,各个节点会定期向其他节点发送PING命令,所请求节点的节点标志会被设置为REDIS_NODE_PFAIL,PFAIL并未离线,但疑似离线。
集群节点将通过发送包含集群中每个节点状态信息的消息来通知其他节点
如果集群中超过一半负责处理槽的主节点拥有master分配如果该节点怀疑离线,则会将该节点标记为离线,并且该节点会将接收命令的节点的集群标志设置为REDIS_NODE_FAIL,以表明集群已离线
节点通知节点 另一个通过发送消息来提供集群中每个节点的状态信息。
此时,离线节点的子节点发现其主节点已被标记为离线,因此该继续前进了。
新的主节点将被撤销 删除原主节点的槽位分配并替换它 这些槽位分配被修改 对于自身来说,即修改集群节点结构和集群状态结构。
新的主节点向集群广播PONG指令。
其他节点就会知道新的主节点已经创建了 clusterNode 结构和 clusterState 结构已经创建并更新了
如果新的主节点会向原剩余的子节点发送新的 SLAVEOF 指令主节点,使其成为自己的子节点
最后一个新的主节点将负责使原始主节点的槽响应工作
我在这里写得很模糊,如果你需要的话。
详细挖掘,你应该阅读这篇文章:
https://redis.cn/topics/cluster-spec.html
或者可以看看《Redis设计与实现》这本非常好的书。
》 黄建红写的。
我也指出了很多。
redis 集群在线迁移
Redis集群在线迁移时,首先需要部署新节点的Redis实例。请注意,该实例只能部署为单节点实例,而不是集群。
旧环境中的操作应与新环境保持一致。
将新节点的Redis添加到旧集群中,并确保其为集群的主节点。
随后,新节点作为从节点添加到集群中。
添加节点后,通过命令查看集群的主从节点信息和状态。
使用`redis-cli-p7000-a'password'clusternodes`命令获取集群节点列表,并确保集群状态显示“ok”。
检查集群中的Master节点,使用`redis-cli-p7000-a'password'clusternodes|grepmaster`命令查看并确认Master节点信息。
接下来执行集群迁移操作。
目标是将所有槽迁移到新节点,node_id:614272e21df1cbbcda117f277ff7baa075b3d15e。
确保插槽在集群中的其余主节点之间均匀分布。
通过检查节点状态和集群信息来验证迁移是否成功。
完成迁移后,注意删除集群中所有旧节点信息,先删除从节点,再删除主节点。
删除节点前,请确保使用del-node命令后旧环境中的Redis进程可以正常关闭,避免集群故障。
最后,检查集群的可用性和数据完整性,以确保迁移操作不会对数据或性能产生负面影响。