浅谈redis主从、哨兵、集群,从部署到了解基本原理

1 篇文章 0 订阅
1 篇文章 0 订阅

为什么使用?

▪️主要考虑服务器压力容灾两个方面。

(1)从服务器压力来说,单台机器的资源是有限的,当数据量大或是请求过多时,一台机器往往扛不住,我们可以把压力分配到多个服务器上,具体的实现就是在多台服务器上部署redis,一起对外提供服务,从客户端的角度来看,服务端背后的集群和单机对客户端提供的服务是一模一样的。

(2)从容灾方面来说,单台机器的redis如果挂掉了,那么整个redis服务就无了,从宕机到恢复这一过程中客户端传过来的请求全部都无法处理,如果是硬盘损坏那redis的持久化文件也都无了,可想而知造成的损失会有多大,如果使用集群,某个节点如果挂掉那么就会有另外一个节点顶上去,在故障恢复的这段时间内损失的只是一小部分数据,用户可能只会认为是网络不好造成的卡顿之类的原因。

主从复制

▪️主从复制用来干嘛?

主数据库用来写,从数据库用来读,分摊读写压力,主数据库进行的写操作会异步复制到从数据库中,主数据库如果挂了,运维人员可以让从数据库来顶替主数据库,让服务可以正常运行,毕竟主数据库的重启到数据恢复是需要很长一段时间的。

▪️主从复制原理

主从复制到主从服务可以正常工作可以大致分为以下几个阶段:
主从复制准备->套接字连接->身份验证->发送端口信息->数据同步->命令传播->心跳检测
在这里插入图片描述

一、主从复制准备:客户端发送slaveof命令将主数据库地址发送给从数据库,从服务器记录好后,向客户端返回OK,表示做好准备。

二、套接字连接
(1)从数据库根据记录好的主数据库地址发送套接字连接。
(2)建立好套接字连接后,从数据库向主数据库发送ping命令,主数据库返回pong,这一步若完成则代表主从数据库之间的网络连接正常,可以正常进行通信。
三、身份验证:若在配置文件中设置了身份验证的相关配置,则需要进行身份验证
四、发送端口信息:身份验证成功后,从数据库会将自己的监听端口号发送给主数据库,主数据库会将其记录起来(在执行info repliacation命令时会显示该端口信息,除此之外暂无其他作用)
五、数据同步
(1)同步分为两种,一种是完整重同步,另一种是部分重同步,这里先介绍完整重同步,后面会介绍另一种。从数据库向主数据库发送PSYNC ? -1命令表示进行完整重同步(发生在首次同步或者不满足部分重同步条件时)
(2)主数据库接收到后,将会异步执行bgsave生成rdb文件,在生成rdb文件期间处理的写命令将会被放入复制积压缓冲区内,并异步将自己的运行id和偏移量发送给从服务器。从服务器接收到运行id后会将其记录下来。rdb文件生成完成后,主数据库将rdb文件+复制积压缓冲区的命令发送给从数据库。
(3)从数据库接收到rdb文件+复制积压缓冲区的命令后,载入rdb文件,然后执行复制积压缓冲区的命令,至此实现了和主数据库相同的状态。
六、命令传播:主数据库处理一个写入命令后,将结果返回给客户端的同时,异步将该命令发送给从数据库执行。
七、心跳检测:在命令传播阶段,从服务器会以每秒一次的频率向主数据库发送replconf ack 复制偏移量,目的是判断:
(1)主从连接状态
(2)主数据库根据复制偏移量判断是否缺失是否需要进行部分重同步
(3)slave_min的判断:
min_slaves_to_write 3 #如果从服务器小于3个则主服务器禁止写入
min_slaves_max_lag 10 #如果三个从服务器的延迟(lag)都>=10,则主服务器禁止写入

▪️部署

(1)结构

在这里插入图片描述

以1主2从的结构进行部署
主:127.0.0.1:6397
从:127.0.01:6398、127.0.0.1:6399

(2)配置文件(其中比较重要的几项)

1.由于本次部署是在单机上操作的,所以不同数据库的配置文件以及其中的部分配置项请提前按名称区分开比如配置文件用redis.端口号.conf区分,pidfile、logfile、dbfilename、appendfilename等配置项的路径。
2.主数据库持久化功能关闭、从数据库持久化功能打开,因为持久化是一个相对耗时耗性能的功能,所以将其放到从数据库去做。
3.进行读写分离,主数据库进行写操作,读操作交给从数据库。

# redis.conf文件中的对应项
appendonly no     # AOF持久化:主数据库设置为no,从数据库设置为yes
save 3600 1       # 自动快照条件:主数据库注释掉,只在从数据库设置
save 300 100
save 60 10000
replica-read-only yes # 从数据库仅可读

(3)启动

# 主数据库正常启动
(base) lyh@MacBook-Pro config % redis-server redis.6397.conf
# 从数据库启动127.0.0.1:6398、127.0.0.1:6399,关联主数据库127.0.0.1:6397
(base) lyh@MacBook-Pro config % redis-server redis.6398.conf --slaveof 127.0.0.1 6397
(base) lyh@MacBook-Pro config % redis-server redis.6399.conf --slaveof 127.0.0.1 6397
# 从数据库第二种启动方式,在配置从数据库的配置文件中添加 replicaof host port
replicaof 127.0.0.1 6397
#小提一句如果之前部署过哨兵,请先检查下每个redis服务的配置文件redis.conf中replicaof这一项是否设置正确,之前我的主redis启动后发现是别的主数据库的从数据库,后来找到原因是哨兵在进行故障恢复的时候,是通过修改replicaof这一项来实现将宕机的旧主数据恢复后变成新主数据库的从数据库的

(4)查看主从关系

# 客户端输入 info replication
127.0.0.1:6397> info replication
# Replication
role:master    # master:主数据库
connected_slaves:2 # 有2个从数据库
# 从数据库的地址以及端口,state:启用状态,offset:偏移量,lag=延迟
slave0:ip=127.0.0.1,port=6399,state=online,offset=6413354,lag=0
slave1:ip=127.0.0.1,port=6398,state=online,offset=6413354,lag=0
master_failover_state:no-failover 
master_replid:e661095d52c2a7a24d9f624d9c1bdf26da75a6ab
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:6413354  # 主数据库的偏移量
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:5364779
repl_backlog_histlen:1048576

(5)读写操作

127.0.0.1:6397> set name lyh   # 主数据库进行写操作
>OK
127.0.0.1:6398> get name       # 从数据库可以读取到主数据库写入到数据
>lyh
127.0.0.1:6398> set name lyh   # 从数据库不可进行写操作
>READONLY You can't write against a read only replica.
127.0.0.1:6399> get name
>lyh
127.0.0.1:6399> set name lyh
>READONLY You can‘t write against a read only replica.

▪️复制偏移量

在这里插入图片描述

当主数据库进行写操作后会在自己的偏移量上加该命令组成字符的字节数,从服务器以及复制积压缓冲缓冲区也是如此,从服务器就可以通过对比偏移量来判断自己的数据状态是否和主数据库相同,若不相同则需要进行同步(接下来会介绍部分重同步)。

▪️复制积压缓冲区:

在这里插入图片描述
在这里插入图片描述

什么是复制积压缓冲区:复制积压缓冲区是一个由主服务器维护的一个固定长度先进先出的队列,默认大小为1mb,既然是固定大小的,当其里面的内容达到1mb后,再往里面添加数据,则最先加入的数据会被推出该队列。主数据库每次在执行写入命令时,除了会将命令异步发送给从服务器外,还会将命令放入复制积压缓冲区中(是按redis的协议以组成这些命令的字符存进去的),每个字符都会有一个复制偏移量。就比如上面的图是一个命令set a 11,存在缓冲区内就是这个样子。

▪️服务器运行id

每个redis服务都有自己的运行id,前面说过从数据库第一次连接主数据库时会记录其运行id,重连后会对比自己记录的运行id还有准备连接的该主数据库的运行id,若不相同,则直接进行完整重同步,若相同,则可以尝试进行部分重同步

▪️部分重同步

(1)什么是部分重同步

完整重同步是需要主服务器执行bgsave,然后将rdb文件以及积压缓冲区的命令一起传给从数据库,从数据库再进行导入,这是非常消耗时间和资源的(这是redis2.8之前的做法),那如果断线重连这段过程中从数据库遗失的数据很少,那还是要走这么一大圈流程?当然不会,为了减少这部分的资源浪费则有了部分重同步,从服务器重连后只需要导入断线期间缺失的命令即可。

(2)什么时候使用部分重同步

从服务器宕机重连,或者网络原因导致命令缺失(通过主从的偏移量是否一致进行判断)

(3)实现原理

在这里插入图片描述

从数据库因宕机重连主数据库时,从数据库将向主数据库发送之前进行首次复制时保存的主数据库的运行id以及自己的偏移量,主数据库将该运行id和自己的进行对比,若不相同则进行完整重同步,若相同则继续读取偏移量,然后将其和复制挤压缓冲区内的偏移量进行对比来决定进行何种复制。具体对比方法如下:
我们之前介绍过了复制积压缓冲区是一个有限长度的队列,将其偏移量看作索引,此时假设队列长度为1000,那么该复制积压缓存区的索引范围可以表示为[x,x+1000],此时假设x = 500,那索引范围 = [500,1500],从数据库发来的偏移量设为index(index<1500),如果index在这段范围内,则只需要将[index,1500]之间的命令发给从数据库执行即可使主从一致,最后主数据库向从数据库返回CONTINUE,表示进行部分重同步,若从数据库的偏移量不在这范围内,则表示从数据库还缺失[index,500]这段区间的命令,可是因为复制积压缓冲区是固定大小的,这部分的数据早就出队了,所以这部分数据获取不到,无法恢复成主从一致,所以主数据库向从数据库发送(+FULLRESYNC 运行id 偏移量)将让其执行完整重同步。

哨兵Sentinel

▪️哨兵工作原理

如果redis服务在运维人员下班的时间宕机了,结果被老板叫起来维护,估计运维人员心里早就骂起来了,为了避免这种情况,redis提供了哨兵模式,故名思义,哨兵就是放哨用的,它主要的作用就是监控主从redis服务,若它监控的主数据库宕机了,其可以自动进行主从切换,这样就可以做到高可用。

▪️哨兵工作流程

初始化->建立和主、从数据库、哨兵的连接->心跳检测->故障转移,主从切换
在这里插入图片描述

一、初始化:
(1)哨兵读取sentinel.conf配置信息,初始化哨兵服务器(其实哨兵服务器就是特殊的redis服务器),将普通redis服务器使用的代码替换成哨兵服务器使用的代码。
二、 建立和主、从数据库、哨兵的连接:
(1)根据初始化阶段读取的主数据库信息,先向主数据库建立两个连接,接着会根据返回信息建立和从数据库、哨兵的连接。下面是关于这2种连接在整个工作流程中的用途
命令连接:
▪️(发现从数据库)每10秒向主数据库发送一次info命令,记录其运行id等相关信息,发现其关联的从数据库,并和从数据库建立命令连接和订阅连接。
▪️每2秒向_sentinel_:hello频道发送自己(哨兵)的相关信息还有自己监控的主数据库相关信息给其他同样监控该主数据库的哨兵记录和更新。
▪️每1秒向其发送ping,监控其运作状态,主要是用来监控主数据库,发现其宕机后及时实施故障补救措施。
▪️在故障转移阶段,从数据库升级为主数据库过程中,哨兵每秒向该从数据库发送一次info命令,观察其角色,直到变为master。
订阅连接:
▪️(发现其他哨兵)接收来自_sentinel_hello频道的信息,用来发现其他监控同一数据库的哨兵,进行信息交换,各自维护共同监控的数据库信息,并和这些哨兵建立命令连接。
三、心跳检测
(1)哨兵会向建立了命令连接的其他对象每秒一次发送ping命令(对象包括主数据库、从数据库、其他哨兵),根据回复值判断其使用状态,若宕机了则会进行相应的补救措施。
▪️有效回复:+PONG、-LOADING、-MASTERDOWN
▪️无效回复:除这三种有效回复以外的回复,或者在限定时间内没有回复
四、故障转移、主从切换
(1)主观下线:在发送ping命令后若主数据库在Sentinel.conf配置文件中的down-after-millisecond项配置的毫秒内向哨兵返回无效回复,则哨兵就会认为该主数据库主观下线。
(2)客观下线:在哨兵认为其监控的主数据库主观下线后,会通过命令连接向其他监控该主数据库的哨兵询问该数据库下线状态(可以是主观下线,也可以是客观下线),若其他哨兵返回的下线数量大于或等于Sentinel.conf中sentinel monitor master host port quorum项的quorum时,则认为该主数据库客观下线,可以进行故障转移。
(3)监控该主数据库的哨兵根据Raft算法选举出领头哨兵。
(4)该领头哨兵根据相关规则在该故障的主数据库关联的从数据库中挑选出最合适的新主数据库,向其发送slaveof no one 命令将其设置为主数据库,在发送完该命令后,每秒发送一次info命令,观察其角色,直到变为master。
(5)该领头哨兵向剩下的所有从数据库发送slaveof host port命令,进行主从复制。
(6)旧主数据库恢复后,哨兵将其发送slaveof host port命令将其设置为新主数据库的从数据库

▪️部署

(1)结构

在这里插入图片描述

(2)配置文件(其中比较重要的几项)

# 被监控主数据库的基本信息
# master-name:自己取的主数据库名字,默认mymaster
# ip:主数据库ip地址
# redis-port:主数据库监听端口
# quorum:判断客观下线条件,若多少个哨兵认为该主数据库下线,则判定为客观下线
sentinel monitor <master-name> <ip> <redis-port> <quorum> 

# 多少秒后没有有效回应ping命令,则认为其主观下线
# master-name:主数据库名字,与之前设置监听的master-name一致
# milliseconds:超时时间,默认30秒
sentinel down-after-milliseconds <master-name> <milliseconds>

# 在进行故障转移主从复制时,最多有多少个从数据库在复制主数据库,若numslaves越小,则完成整个主从复制的流程就越长,理解为此时有5个从数据库需要进行主从复制,这个值设置为1,则每次只能有一个从数据库进行主从复制,整个流程就会被拉长,若想要时间变短就需要把这个值设置得比较大,不过这个值设置得越大,那从数据库不可用的数量就会增多,因为在主从复制时从数据库是阻塞的。按照业务需求自己拿捏吧
sentinel parallel-syncs <master-name> <numslaves>

# 通知型脚本:当sentinel有任何警告级别的事件发生时(比如说redis实例的主观失效和客观失效等等),将会去调用这个脚本,如果sentinel.conf配置文件中配置了这个脚本路径,那么必须保证这个脚本存在于这个路径,并且是可执行的,否则sentinel无法正常启动成功。
sentinel notification-script <master-name> <script-path> 

# 当一个master由于failover而发生改变时,这个脚本将会被调用,通知相关的客户端关于master地址已经发生改变的信息。以下参数将会在调用脚本时传给脚本:
sentinel client-reconfig-script <master-name> <script-path>

(3)启动

(base) lyh@MacBook-Pro sentinel % redis-sentinel sentinel.conf

集群

▪️为什么使用集群?

虽然部署主从复制之后可以做到容灾高可用,但此时所有的数据库都需要存储一份完整的数据,由此看来容量最小的那个数据库就成了存储量的瓶颈。使用redis的集群功能可以解决这一点,它可以将一份完整的数据库分给不同的redis服务,每一个redis服务只需要管理自己的那份数据就好,并且对于客户端来说是透明的,不用关心存储和查询是在哪个redis服务上操作的

▪️原理

(1)节点

一个集群是由多个节点组成,组成该集群的redis服务中,一个redis服务表示一个节点。

(2)初始化

初始化阶段:客户端通知->握手->槽指派->初始化完成

在这里插入图片描述

(1)客户端通知:各个redis开启集群功能后,会成为一个独立的节点,客户端通过向某一节点发送 cluster meet 目标地址 目标端口 命令,让源节点(节点1)将目标节点纳入自己的集群中。
(2)握手:源节点接收到cluster meet后准备与目标节点进行套接字连接(握手),源节点先向目标节点发送meet消息,目标节点接收到后,返回PONE消息表示接收到了源节点的meet命令,此时源节点再对目标节点发送PING消息,目标节点接收到后握手完成,之后源节点会通过Gossip协议通知集群中的其他节点与目标节点握手,最后目标节点加入集群。
(3)槽指派:节点加入集群后,需要将16384个槽分配给每个节点,每个槽都会用来存储客户端写入的键以及对应的值。这样就把一份完整的数据切割给不同的节点管理了,容量最小的节点不再会是整个集群存储量的瓶颈
(4)初始化完成:所有的槽都分配完成后,初始化完成。

(3)处理命令(hash一致性算法)

在这里插入图片描述

当客户端向某个节点发送命令时,该节点会先将该key用CRC16算法求hash,然后再对其求模,得到的值就是槽点,该节点根据计算出来的槽点判断是否属于自己管理的槽点,若属于则执行该命令,若不属于查询该槽属于哪个节点管理,查询到地址后便向客户端返回正确的节点信息,客户端再对这个正确节点发送同样的命令。

(4)重新分片

可能你已经想问,如果中途想要加入新的节点,槽该怎么分配,都看到这了就来了解一下。

在这里插入图片描述
(1)发送cluster setslot importing让目标节点做好准备导入源节点槽点的数据。
(2)发送cluster setslot migrating让源节点做好将槽点slot的数据迁移到目标节点的准备。
(3)发送cluster getkeysinslot 命令,获取源节点对应槽点的最多count个键值对。
(4)发送migrate,向目标节点原子的迁移步骤(3)获取的键值对。
(5)根据migrate命令的键值对进行迁移。
(6)重复(3)、(4)、(5),所有的键值对迁移完成后,发送cluster setslot node命令,让源节点把槽指派给目标节点 。
(7)将自己的槽指派给目标节点。
(8)步骤1-7是一个槽点流程,如果要迁移多个槽则对每个槽重复步骤1-7即可。

整个过程并不需要下线redis服务,它可以边迁移,边处理客户端的命令,具体流程如下:
一、迁移过程中,对源节点发送命令
在这里插入图片描述
(1)客户端命令发送到源节点(设定该命令正好就属于该源节点管理的槽点)
(2)源节点首先判断该key是否存在自己的数据库中
(3)若存在则执行,若不存在则会去判断是否在进行迁移(在迁移时redis会记录一个状态,表示正在迁移中)。
(4)若正在迁移则表示可能该key-value已经迁移到目标节点中了,此时向客户端返回ACK信息,客户端收到该信息后会根据该信息提供的目标节点地址进行转向,对该目标节点再次发送命令。
二、迁移过程中对目标节点发送命令
在这里插入图片描述
(1)目标节点首先会判断该命令所在的槽是否属于自己,如果存在则执行,如果不存在则判断是否正在进行对该命令所在槽的迁移。
(2) 如果没有在进行迁移则返回move信息给客户端,客户端转向至对应的节点再次发送该命令。如果在进行迁移,则说明该命令操作的键值对已经迁移过来了只是槽点还没指派过来,接着判断客户端发送这个命令时是否带有ASKING标识。
(3)若有ASKING标识符则执行该命令,若没有则返回move信息给客户端,进行转向。(ASKING标识符是一次性的,每次命令结束后该标识符就会消失,客户端需要重新标识符)

(5)复制和故障转移

一、复制:和最开始介绍的主从复制一样,从数据库会复制主数据库的数据库(槽还是指派给的主数据库)。
二、故障转移
(1)故障检测
疑似下线(PFALL):集群中每个节点会定期向其他节点发送PING消息,若超过规定时间没有返回PONG,则发送PING消息的节点就会判定接收PING消息的节点为疑似下线。然后该发送者会向其他节点公开仪式下线服务器的信息。
下线(FALL):集群中其他节点接收到疑似下线的信息后,各个节点也会判断该节点是否疑似下线,如果判断为疑似下线的节点数超过一半,则第一个判断为疑似下线的节点会向集群广播该节点下线
(2)故障转移:该下线主节点的从节点接收到自己的主节点下线的通知后, 会在从节点中根据Raft算法选举出新的主节点。然后选举出来的从节点执行slaveof no one命令升级为新主节点,新主节点会撤销旧主节点被指派的槽点并将这些槽点指派给自己。指派完成后向其他节点发送PONG消息,表示自己已经成为了新主节点,转移完成。旧主节点恢复后会成为新主节点的从节点。

▪️部署

(1)前期准备:

(1)一个集群需要至少3个主数据库才可启用,我们用3主3从的结构部署
(2)准备6个redis.conf配置文件,名称路径自定义。
在这里插入图片描述

redis.6380.conf

cluster-enabled yes	# 开启集群功能
cluster-config-file nodes-6380.conf #每个节点的状态都会记录在里面,该项的值需要区分开,若存在相同名称的该文件,则会启动失败。
cluster-node-timeout 15000 # 表示当某个节点持续 timeout 的时间失联时,才可以认定该节点出现故障,需要进行主从切换。如果没有这个选项,网络抖动会导致主从频繁切换(数据的重新复制)。

(2)启动节点

在这里插入图片描述

# 连接客户端查看集群开启情况:
127.0.0.1:6380> info cluster
# Cluster
cluster_enabled:1        # 集群状态开启
127.0.0.1:6380> cluster info 
cluster_state:fail        # 因为槽没有分配完,所以集群不能正常使用
cluster_slots_assigned:0  # 被分配的槽位数
cluster_slots_ok:0        # 正确分配的槽位
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:1     # 当前1个节点(现在节点都还是独立状态)
cluster_size:0
cluster_current_epoch:0
cluster_my_epoch:0
cluster_stats_messages_sent:0
cluster_stats_messages_received:0

(3)关联节点

127.0.0.1:6380> cluster meet 127.0.0.1 6381 # 将节点(127.0.0.1:6381)加入到集群
OK
127.0.0.1:6380> cluster meet 127.0.0.1 6382 # 将节点(127.0.0.1:6381)加入到集群
OK
127.0.0.1:6380> cluster info
cluster_state:fail
cluster_slots_assigned:0
cluster_slots_ok:0
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:3   # 3个节点
cluster_size:0
cluster_current_epoch:2
cluster_my_epoch:1
cluster_stats_messages_ping_sent:81
cluster_stats_messages_pong_sent:84
cluster_stats_messages_meet_sent:2
cluster_stats_messages_sent:167
cluster_stats_messages_ping_received:84
cluster_stats_messages_pong_received:83
cluster_stats_messages_received:167

(4)槽指派

# 在127.0.0.1:6380节点的客户端中进行槽指派,也可以在命令行直接执行
127.0.0.1:6380> cluster addslots 0
>OK # 槽指派成功
# 等同于在各个客户端的命令行执行cluster addslots,接下来为了方便都以下面这种方式进行槽指派
MacBook-Pro config % redis-cli -p 6380 cluster addslots 0
>(error) ERR Slot 0 is already busy # 表示槽位0已经被分配

# 将1-5061槽指派给127.0.0.1:6380 $(seq x y)可以按范围分配
MacBook-Pro config % redis-cli -p 6380 cluster addslots $(seq 1 5061)
>OK

# 将5062-10922槽指派给127.0.0.1:6380(本来想指派给6381节点的,但是输错了,又指派给6380节点了,不过没关系,后面正好介绍槽迁移)
MacBook-Pro config % redis-cli -p 6380 cluster addslots $(seq 5062 10922)
>OK

# 将10923-16383槽分配给127.0.0.1:6383
MacBook-Pro config % redis-cli -p 6382 cluster addslots $(seq 10923 16383)
>OK

(5)槽迁移

# 将分配错的5062-10922,从6380节点迁移到6381节点

# 获取节点信息(返回的响应我删除了一些信息)响应由运行id+节点地址信息+槽范围组成
MacBook-Pro config % redis-cli -p 6380 cluster nodes
>32a23a32db83211f1963e21c310cefe7540bd8b4 127.0.0.1:6380@16380 0-10922
>a9f817469aa53b841faed7bee997bf89d0e68cef 127.0.0.1:6382@16382 10923-16383
>98bc7738cdc5a0f238a228e491d1773c8edaddf4 127.0.0.1:6381@16381

#(1)获取槽的运行id
6380 = 32a23a32db83211f1963e21c310cefe7540bd8b4
6381 = 98bc7738cdc5a0f238a228e491d1773c8edaddf4
6382 = a9f817469aa53b841faed7bee997bf89d0e68cef


#(2)让目标节点做好迁入的准备(5062槽):cluster setslot <槽> importing <目标节点的运行id>
redis-cli -p 6380 cluster setslot 5062 importing 98bc7738cdc5a0f238a228e491d1773c8edaddf4
>OK

#(3)让源节点做好迁出的准备(先迁出一个5062槽试试):cluster setslot <槽> migrating <源节点的运行id>
redis-cli -p 6380 cluster setslot 5062 MIGRATING 32a23a32db83211f1963e21c310cefe7540bd8b4
>OK

#(4)获取源节点5062槽的100个key(因为我们没有写入命令,所以为空)
redis-cli -p 6380 cluster getkeysinslot 5062 100
(empty array)

#(5)迁移步骤(4)获取的key:MIGRATE <目标节点的host> <目标节点的port> <key|""> <数据库> <timeout> [KEYS key [key ...]]
redis-cli -p 6380 migrate 127.0.0.1 6381 "" 0 5000 keys key1 key2
# <key|"">: key表示key名,此次操作只迁移一个key,如果这一项为"",则为多key迁移,在后面的KEYS项添加需要迁移的多个key
>NOKEY #返回这个表示没有key

#(6)通知其他节点迁移完成: redis-cli -p 6380 cluster setslot <槽> node <需要通知的节点的运行id> 
redis-cli -p 6380 cluster setslot 5062 node  98bc7738cdc5a0f238a228e491d1773c8edaddf4
redis-cli -p 6380 cluster setslot 5062 node  a9f817469aa53b841faed7bee997bf89d0e68cef

#(7)查看迁移情况({6080:"0-5061,5063-10922",6081:"5062",6082:"10923-16383"})
MacBook-Pro config % redis-cli -p 6380 cluster nodes
32a23a32db83211f1963e21c310cefe7540bd8b4 127.0.0.1:6380@16380 0-5061 5063-10922
98bc7738cdc5a0f238a228e491d1773c8edaddf4 127.0.0.1:6381@16381 5062
a9f817469aa53b841faed7bee997bf89d0e68cef 127.0.0.1:6382@16382 10923-16383
#重复以上步骤1-6将剩下的5063-10922的槽迁移给6081节点即可(。。。。当然不会这样做,可以自己写脚本完成,也可以用redis提供redis-trib完成,redis5.0之后取消了这个脚步,把它的功能迁移到了redis-cli --cluster中去了,大家可以去了解一下,这里就不做演示)
redis-cli --cluster reshard 127.0.0.1:6380 --cluster-from 32a23a32db83211f1963e21c310cefe7540bd8b4 --cluster-to 98bc7738cdc5a0f238a228e491d1773c8edaddf4 --cluster-slots 5062 --cluster-yes  --cluster-timeout 5000 --cluster-pipeline 10 --cluster-replace

>Moving slot 0 from 127.0.0.1:6380 to 127.0.0.1:6381
>..................中间有5062条信息
>Moving slot 5062 from 127.0.0.1:6380 to 127.0.0.1:6381

#检查一下槽分配情况,确实从6380节点分配了5062个槽到6381节点
redis-cli -p 6380 cluster nodes  
32a23a32db83211f1963e21c310cefe7540bd8b4 127.0.0.1:6380@16380 5061-5062 5064-10922
a9f817469aa53b841faed7bee997bf89d0e68cef 127.0.0.1:6382@16382  10923-16383
98bc7738cdc5a0f238a228e491d1773c8edaddf4 127.0.0.1:6381@16381 0-5060 5063

(6)主从关联

# 将从节点添加进集群:在随便一个主节点客户端执行即可,或者在命令行用redis-cli -p 6380 cluster meet host:port
127.0.0.1:6380> cluster meet 127.0.0.1 6383
OK
127.0.0.1:6380> cluster meet 127.0.0.1 6384
OK
127.0.0.1:6380> cluster meet 127.0.0.1 6385

# 在每个从节点的客户端关联主节点:cluster replicate <主节点运行id>
# 主6380-从6383,主6381-从6384,主6383-从6385
127.0.0.1:6383> cluster REPLICATE 32a23a32db83211f1963e21c310cefe7540bd8b4
OK
127.0.0.1:6384> cluster replicate 98bc7738cdc5a0f238a228e491d1773c8edaddf4
OK
127.0.0.1:6385> cluster replicate a9f817469aa53b841faed7bee997bf89d0e68cef
OK

#查看节点信息,可以看出已经关联成功,在每一个从节点的信息中可以看到主节点的运行id
127.0.0.1:6380> cluster nodes
>c3f5d11da4cd52ea1b52ec390253425cad60b4bf 127.0.0.1:6384@16384 slave 98bc7738cdc5a0f238a228e491d1773c8edaddf4 0 1624086397000 4 connected #6384 
>f50cc99e2034a3711ef8a7842a10d8ed06e001cb 127.0.0.1:6385@16385 slave a9f817469aa53b841faed7bee997bf89d0e68cef 0 1624086396000 6 connected #6385
>896242246c43fc71ef82d038d186d82b39d3aaef 127.0.0.1:6383@16383 slave 32a23a32db83211f1963e21c310cefe7540bd8b4 0 1624086396000 3 connected #6383
>32a23a32db83211f1963e21c310cefe7540bd8b4 127.0.0.1:6380@16380 myself,master - 0 1624086395000 3 connected 5061-5062 5064-10922 	   #6380
>98bc7738cdc5a0f238a228e491d1773c8edaddf4 127.0.0.1:6381@16381 master - 0 1624086397532 4 connected 0-5060 5063 #6381
>a9f817469aa53b841faed7bee997bf89d0e68cef 127.0.0.1:6382@16382 master - 0 1624086396000 6 connected 10923-16383 #6382

(7)命令测试

# 在普通模式下的客户端设置键值对 name = lyh
127.0.0.1:6380> set name lyh
OK
127.0.0.1:6380> get name
"lyh"

# 现在去它的从节点6383获取一下这个key,普通客户端直接返回moved而没有提供重定向
127.0.0.1:6383> get name
MOVED 5798 127.0.0.1:6380

# 用集群模式的客户端试一下,redis-cli -c (-c开启集群模式),发现可以自动重定向
MacBook-Pro config % redis-cli -c -p 6383
127.0.0.1:6383> get name
-> Redirected to slot [5798] located at 127.0.0.1:6380
"lyh"

# 在其他节点获取不属于自己槽的key时也是同样的情况,这里就不测试了

(8)故障转移

# 现在将主节点6380下线后看一下集群节点信息
MacBook-Pro config % redis-cli -p 6381 cluster nodes
>f50cc99e2034a3711ef8a7842a10d8ed06e001cb 127.0.0.1:6385@16385 slave a9f817469aa53b841faed7bee997bf89d0e68cef 0 1624087315595 6 connected
>98bc7738cdc5a0f238a228e491d1773c8edaddf4 127.0.0.1:6381@16381 myself,master - 0 1624087314000 4 connected 0-5060 5063
>c3f5d11da4cd52ea1b52ec390253425cad60b4bf 127.0.0.1:6384@16384 slave 98bc7738cdc5a0f238a228e491d1773c8edaddf4 0 1624087313570 4 connected
>32a23a32db83211f1963e21c310cefe7540bd8b4 127.0.0.1:6380@16380 master,fail - 1624087241641 1624087238000 3 disconnected # 6380这个节点已经有了fail标识符,表示已下线
>a9f817469aa53b841faed7bee997bf89d0e68cef 127.0.0.1:6382@16382 master - 0 1624087316609 6 connected 10923-16383
>896242246c43fc71ef82d038d186d82b39d3aaef 127.0.0.1:6383@16383 master - 0 1624087313000 8 connected 5061-5062 5064-10922 #6380的从节点6383升级为了主节点

# 在节点6382执行下get name命令,可以发现现在重定向到了6383节点,6383节点已完成故障转移
127.0.0.1:6382> get name
MOVED 5798 127.0.0.1:6383

# 现在恢复6380节点后查看集群节点信息
MacBook-Pro config % redis-cli -p 6381 cluster nodes
>f50cc99e2034a3711ef8a7842a10d8ed06e001cb 127.0.0.1:6385@16385 slave a9f817469aa53b841faed7bee997bf89d0e68cef 0 1624087637151 6 connected
>98bc7738cdc5a0f238a228e491d1773c8edaddf4 127.0.0.1:6381@16381 myself,master - 0 1624087635000 4 connected 0-5060 5063
>c3f5d11da4cd52ea1b52ec390253425cad60b4bf 127.0.0.1:6384@16384 slave 98bc7738cdc5a0f238a228e491d1773c8edaddf4 0 1624087637000 4 connected
>32a23a32db83211f1963e21c310cefe7540bd8b4 127.0.0.1:6380@16380 slave 896242246c43fc71ef82d038d186d82b39d3aaef 0 1624087636140 8 connected	# 6380节点已恢复,并且成为了6383的从节点(通过slave+关联的主节点id可以看出来)
>a9f817469aa53b841faed7bee997bf89d0e68cef 127.0.0.1:6382@16382 master - 0 1624087638163 6 connected 10923-16383

>896242246c43fc71ef82d038d186d82b39d3aaef 127.0.0.1:6383@16383 master - 0 1624087635127 8 connected 5061-5062 5064-10922

总结

主从、哨兵、集群是三种不同的模式, 哨兵可以让主从模式从发现故障到故障转移都变成自动的。在集群模式下,也具有和哨兵同样的功能,自动发现主节点故障,然后进行故障转移,但是还是存在一定的区别:
集群模式:当主节点挂掉,从节点会向集群中其他主节点通信,申请成为主节点。
哨兵模式:主节点挂掉,从节点不做动作,选举的动作交给哨兵,哨兵从从节点中选一个当master。
所以二选一即可

tips:若有不对的地方欢迎指正。

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值