从Redis主从架构模式角度说一说是如何支持高并发的

从Redis主从架构模式角度说一说是如何支持高并发的

我们说Redis是基于内存操作的数据库,追求的是简单高效,实现了高性能的数据访问。单机Redis所能支持的QPS一般都在几万左右,一般不会超过10w+,但是,在有些实际业务中,像是秒杀、双十一,这些业务场景的QPS很有可能达到惊人的数字!所以说高并发场景下的单机Redis显得就有些吃力了,不用怕,Redis官方早就想到了高并发的场景,我们可以使用多个Redis实例,搭建主从架构模式来支撑高并发的场景。

主从架构模式,也就说有一台Redis服务器做主机,多台Redis服务器做从机,形成一个主从架构,主机主要来用执行写操作,而从机主要用来执行读操作,从而实现读写分离,缓解了单个服务器处理过多请求的压力。主机就像是“老大”,只要负责一些重要的写操作,而一些读操作,并没有修改数据库中的数据,就交给从机这些“小弟们”去处理就可以了。但是必须要保证主机和从机的数据的一致性,这依赖于Redis的主从复制机制。接下来就来说一下主从复制。

我们执行slaveof命令,就可以使得当前Redis服务器成为指定的那个Redis服务器的从机,然后从机会复制主机的数据,保证主从数据库状态的一致性。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uU2Hhvhq-1632467233862)(C:\Users\Jian\AppData\Roaming\Typora\typora-user-images\image-20210923212914616.png)]

在Redis 2.8版本以前,Redis复制功能分为同步命令传播两个操作

  • 同步:将从服务器的数据库状态更新至主服务器当前所处的数据库状态
  • 命令传播:在主服务器的数据库状态被修改,导致主从服务器的数据库状态出现不一致时,使得主从服务器数据库状态重新回到一致状态。

也就是说,当主服务器修改数据库中的数据时,会通过命令传播告知从服务器数据库状态已经被修改了,从服务器就会对主服务器进行同步操作,使得主从服务器重新恢复到数据一致性。

同步操作

从服务器对主服务器进行同步操作需要通过向主服务器发送SYNC命令来完成:

  1. 从服务器向主服务器发送SYNC命令
  2. 主服务器收到SYNC命令之后会执行BGSAVE命令,创建一个子进程在后台生成一个RDB文件,并使用一个缓冲区记录从现在开始执行的所有写命令。之所以还需要缓冲区记录写命令,是因为很有可能在生成快照的这段时间内,主服务器又执行了某些写命令,导致数据库状态发生了修改,对于这些修改也需要同步到从服务器中。
  3. 当主服务器执行完BGSAVE命令之后,主服务器会将生成的RDB文件发送给从服务器,从服务器接收并加载这个RDB文件,将自己的数据库状态更新至主服务器执行BGSAVE命令时的数据库状态,也就是将主服务器执行BGSAVE命令时的数据库快照,原封不动的复制给了从服务器。
  4. 主服务器将记录在缓冲区里面的所有写命令发送给从服务器,从服务器执行这些写命令,将自己的数据库状态更新至主服务器当前数据库状态。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v3tzBOnx-1632467233866)(C:\Users\Jian\AppData\Roaming\Typora\typora-user-images\image-20210923220037329.png)]

由此可见,主从复制依赖于Redis持久化机制,通过SYNC+RDB文件+缓冲区写命令完成了主从复制!

那么从服务器如何知道什么时候执行同步操作呢?这就需要主服务器对从服务器执行命令传播操作。这就像“老大”给“小弟们”下达命令,然后“小弟们”收到命令后,执行同步操作紧跟“老大”的步伐。

命令传播

当主服务器执行客户端发送来的写命令时,主服务器的数据库状态就可能发生改变,这就会导致主从服务器数据库状态不一致的情况。为了让主从服务器数据库状态保持一致,主服务器需要对从服务器执行命令传播操作,主服务器将自己执行的写命令发送给从服务器并执行,当从服务器执行完主服务器发送来的写命令之后,主从服务器就会又回到一致状态。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-biJONR0Y-1632467233869)(C:\Users\Jian\AppData\Roaming\Typora\typora-user-images\image-20210923221421814.png)]

上面就是Redis旧版本的主从复制的实现原理,但是这样主从复制存在效率低的缺陷。

当主从服务器断开连接,从服务器重新连接上主服务器时,从服务器会向主服务器再次发送SYNC命令请求同步。主服务器会再次重新生成全量的RDB文件并传送给从服务器,从服务器会再次加载RDB文件以及主服务器缓冲区执行过的写命令,从而再次达到同步状态。

但是在断开重连期间,主服务器执行的写命令一般相对整个数据库数据量要少的多,为了让从服务器弥补这一小部分缺失的数据,重新全量复制执行RDB文件,性能非常的低效。

在Redis 2.8版本之后,为了解决旧版的主从复制低效的问题,新版本的Redis使用PSYNC命令代替了SYNC命令来执行复制时的同步操作!SYNC命令是一个完整重同步命令,而PSYNC命令既能实现完整重同步也能实现部分重同步

  • 完整重同步模式

    PSYNC命令的完整重同步主要用于初次复制的情况,完整重同步的执行过程基本和SYNC命令一样,都是通过主服务器向从服务器发送全量的RDB文件,以及发送保存在缓冲区里面的写命令来实现同步操作的。

  • 部分重同步模式

    部分重同步主要用于处理从机断线重连以后再次进行复制的情况,当从服务器断线重连之后,主服务器可以将从服务器断开期间执行的写命令发送给从服务器,从服务器只需要接收并执行这些命令,就可以将数据库状态更新至主服务器当前所处的状态。

接下来我们就来讲讲这个部分重同步是如何实现的。

部分重同步的实现

有了部分重同步,当从服务器断线重连再次进行复制时,就不用全量复制RDB以及缓冲区里面的写命令了,还是只需要执行主服务器发送来的断线期间执行过的写命令即可,这也称为增量复制。

要想实现部分重同步必须要有以下3个部分:

  • 主服务器的赋值偏移量和从服务器的复制偏移量
  • 主服务器的复制积压缓冲区
  • 服务器的运行ID
复制偏移量

主服务器和从服务器都会维护一个复制偏移量,主要是用来记录当前复制到了哪个地方了,方便断线重连后续传。

主服务器每次向从服务器发送N个字节的数据时,就将自己的复制欧阳路加上N,从服务器每次接收到主服务器发送来的N个字节的数据时,也会将自己的复制偏移量加上N,通过对比主从服务器的复制偏移量,就可以很容易知道主从服务器是否处于一致状态。断线状态的从服务器的复制偏移量要小于主服务器的复制偏移量。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-B5rK1dMc-1632467233871)(C:\Users\Jian\AppData\Roaming\Typora\typora-user-images\image-20210923225241758.png)]

复制积压缓冲区

当从服务器断线时,主服务器执行的写命令需要保存在复制积压缓冲区里面,这个缓冲区是由主服务器维护的一个固定长度、FIFO先进先出的队列。当主服务器进行命令传播时,它会将写命令发送给所有从服务器,同时还会将写命令入队到复制积压缓存区里面,目的就是为了给断线重连的从服务器再次进行续传。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FGBPyMTM-1632467233874)(C:\Users\Jian\AppData\Roaming\Typora\typora-user-images\image-20210923225659383.png)]

主服务器的复制积压缓冲区里面保存着一部分最近传播的写命令,并且赋值积压缓冲区会为队列中的每个字节记录对于的复制偏移量,也是为了方便续传。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8qCJsWhM-1632467233875)(C:\Users\Jian\AppData\Roaming\Typora\typora-user-images\image-20210923225834963.png)]

当从服务器重新连接上主服务器时,从服务器会通过PSYNC命令将自己的复制偏移量发送给主服务器,告诉主服务器自己在断线之后复制到哪个地方了,主服务器就会根据这个复制偏移量来决定如何进行同步操作。

  • 如果复制偏移量之后的数据仍然存在于复制积压缓冲区里面,那么主服务器将对从服务器发送continue命令并进行部分重同步操作,发送给从服务器断线期间缺失的那部分数据。
  • 如果复制偏移量之后的数据已经不存在于复制积压缓冲区里面了,那么主服务器将对从服务器进行完整重同步

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kWoQh1Mh-1632467233883)(C:\Users\Jian\AppData\Roaming\Typora\typora-user-images\image-20210923232321104.png)]

服务器运行ID

我们所说的主从架构模式,有可能是存在多个从服务器,而每个Redis服务器都会有自己的运行ID,用来标识自己的身份。这个运用ID是在服务器启动时自动生成的,由40个随机的十六进制字符组成。

当从服务器对主服务器进行初次复制时,主服务器会将自己的运行ID传送给从服务器,而从服务器会将这个运行ID保存起来。当从服务器断线重连上一个主服务器时,从服务器将会向当前连接的主服务器发送之前保存的主服务器的运行ID。如果从服务器保存的主服务器运行ID和当前连接的主服务器的运行ID相同,那么说明从服务器断线之前复制的就是当前接连的这个主服务器,主服务器可以继续执行部分重同步操作。如果发现运行ID不相同,说明从服务器断线重新连接的不是之前那个主服务器了,因此主服务器将对从服务器进行完整重同步操作

所以说导致完整重同步操作有3种情况:

  • 一是初次复制
  • 二是从服务器断线缺少的那部分数据已经不存在于主服务器的复制积压缓冲区里面了
  • 三是主服务器运行ID不相同了,也就是说从服务器“易主”了

我们说PSYNC命令在Redis新版本中替代了SYNC命令,并且支持部分重同步,接下来我们就来看看PSYNC命令是如何实现的。

PSYNC命令的实现

我们说过了PSYNC命令支持完整重同步和部分重同步。

如果从服务器初次复制主服务器,从服务器在向主服务器发送PYSNC命令的时候会带上一个-1,用来标识此次需要进行完整重同步。

如果从服务器已经复制过主服务器了,那么再下一次开始新的复制时,将会向主服务器发送PYSNC同步命令的时候带上从服务器的复制偏移量上一次复制的主服务器运行ID。根据这两个参数,主服务器会决定是执行完整重同步还是部分重同步(缺少的数据不存在于复制积压缓冲区、运行ID不一致,都会导致完整重同步!)。

主服务器接受到PSYNC命令之后,会向从服务器回复。如果回复的是FULLRESYNC说明需要执行完整重同步,如果回复的是continue说明执行部分重同步。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-49kd98Gi-1632467233886)(C:\Users\Jian\AppData\Roaming\Typora\typora-user-images\image-20210924031051818.png)]

我们发现即使PSYNC替代了SYNC提高了主从复制的效率,但是当从服务器发生故障宕机时,重启的时候还是有可能会导致完整重同步,进行全量复制。为了解决这个问题,Redis 4.0 又一次对PSYNC命令进行了优化,称为PSYNC2

PSYNC2相比于PSYNC进行了2处优化:

  • 引入了两个复制id和复制偏移量

    • 第一组是replid和master_replid_offset(解决重启后导致完整重同步的问题)

    主服务器用来记录自己的复制ID和复制偏移量

    从服务器用来记录自己正在同步的主服务器的复制ID和复制偏移量

    • 第二组是replid2和second_repl_offset(解决故障切换后导致完整重同步的问题)

      主从服务器都是用来记录上一个主服务器的复制ID和复制偏移量,新master和slave在故障前的master是相同的。主要用于故障切换时支持部分重同步。

  • 从服务器也会开启复制积压缓冲区

    主要用于故障切换后,从服务器升级为主服务器,使得这个从服务器仍然可以通过复制积压缓冲区继续支持部分重同步。

所以,PSYNC2命令的优化主要考虑了两点。一是从机断线或者主机故障导致原来的主从关系发生了改变;二是主从关系交换,从机升级为主机。

主从复制的实现过程

介绍了主从复制的同步和命令转播操作之后,接下来我们就来看看从发送slaveof命令开始到复制结束的详细流程。

步骤1:设置主服务器的地址和端口

当客户端向当前服务器发送SLAVEOF [ip] [sort]命令时,就说明要准备和指定的服务器构建主从关系。当前服务器作为从服务器,并且从服务器还需要将ip地址和端口号保存到从服务器状态的masterhostmasterport这两个属性里面。slaveof命令是一个异步命令,在完成masterhost属性和masterport属性的设置工作之后,从服务器将会向客户端返回OK,表示已成功执行完slaveof命令。而实际上复制工作将在返回OK之后才真正开始执行。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c6Dp4qZy-1632467233890)(C:\Users\Jian\AppData\Roaming\Typora\typora-user-images\image-20210924132926160.png)]

步骤2:建立套接字连接

从服务器保存了主服务器的ip地址和端口号,接下来就会向主服务器创建套接字连接。

如果从服务器成功创建套接字连接,那么从服务器将为这个套接字关联一个专门用来处理复制工作的文件事件处理器,这个处理器将负责执行后续的复制工作,比如接收RDB文件。

不用怕会有大量的套接字创建连接,我们之前说过虽然Redis是单线程模型,但是它采用了I/O多路复用技术来监听大量的套接字连接,维护了一个套接字队列,同时通过文件事件分派器给每个文件事件分配一个对应的事件处理器。当一个套接字被对应所关联的事件处理器执行完成之后,I/O多路复用程序才会继续向文件事件分派器传送下一个套接字。并且引入了多线程概念来处理读取文件和写回结果。所以无需担心Redis在有大量套接字创建连接时的性能。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NEVL0ULQ-1632467233893)(C:\Users\Jian\AppData\Roaming\Typora\typora-user-images\image-20210822102630124.png)]

主从服务器成功建立套接字连接之后,从服务器可以向主服务器发送请求命令,主服务器也可以向从服务器返回命令

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FkmbsM7C-1632467233894)(C:\Users\Jian\AppData\Roaming\Typora\typora-user-images\image-20210924134512889.png)]

步骤3:发送PING命令

套接字创建连接成功之后,从服务器会向主服务器发送一个PING命令。

这个PING命令有两个作用:

  • 虽然主从服务器成功创建了套接字连接,但是双方还没有使用套接字进行过任何通信,通过发送PING命令可以检查套接字的读写状态是否正常
  • 接下来的复制工作都是建立在主从服务器能够正常处理命令请求基础下,通过发送PING命令可以检查主从服务器是否能够正常处理命令。

如果从服务器收到主服务器回复的PONG命令,说明主从服务器之间的连接是正常的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gah9P2nk-1632467233895)(C:\Users\Jian\AppData\Roaming\Typora\typora-user-images\image-20210823140158858.png)]

步骤4:身份验证

从服务器接收到主服务器返回的PONG命令之后,从服务器可以向主服务器发送一条AUTH身份验证命令。

只有主服务器设置了requirepass选项并且从服务器AUTH发送的密码和主服务器requirepass选项设置的密码相同,那么主从服务器才可以继续工作。

如果主从服务器都没有设置密码,则无需进行身份验证就可以继续工作。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fU5qH3YL-1632467233898)(C:\Users\Jian\AppData\Roaming\Typora\typora-user-images\image-20210924140241946.png)]

步骤5:发送端口信息

验证身份之后,从服务器向主服务器发送从服务器的监听端口号命令,主服务器接收到这个命令之后,会保存从服务器的监听端口号,这样主服务器就可以知道哪些服务器是自己的从机,也就是说知道自己都和哪些服务器是主从关系。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Qg5vTcp0-1632467233902)(C:\Users\Jian\AppData\Roaming\Typora\typora-user-images\image-20210924140825052.png)]

步骤6:同步

主从服务器互相保存了对方的信息并且能够正常进行通信之后,从服务器向主服务器发送PSYNC命令,执行同步操作。

无论执行完整重同步还是部分重同步,主服务器都需要成为从服务器的客户端,这样才能将保存在缓冲区里面的写命令,或者保存在赋值积压缓冲区里面的写命令,发送给从服务器。

至于PYSNC命令的执行过程和实现,我们上面已经讲过了。

同步操作执行完成之后,主从服务器互为对方的客户端,可以互相向对方发送命令请求,或者互相向对方回复命令。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G81BGgX8-1632467233906)(C:\Users\Jian\AppData\Roaming\Typora\typora-user-images\image-20210924141506406.png)]

步骤7:命令传播

当完成同步操作之后,主从服务器就会进入到命令传播阶段,这个阶段主服务器只要是执行过写命令,就会将这些写命令发送给从服务器。从服务器接收到这些写命令并执行。这样就可以一直保持主从一致性了!

在命令传播阶段,从服务器默认会以每秒一次的频率,向主服务器发送replconf ack <replication_offset>命令,这称为心跳检测

为什么要进行心跳检测?

  • 检测主从服务器的网络连接状态

    我们说命令传播阶段时持续进行的,这样才能一直保持主从的一致性。为了保证主从服务器的网络畅通,主从服务器通过发送和接受replconf ack命令来检查二者之间的网络连接是否正常,如果主服务器超过一秒钟没有收到从服务器发来的心跳检测命令,那么主服务器就知道主从服务器之间的连接出现了问题。

  • 检测命令丢失

    如果因为网络故障,主服务器传播给从服务器的写命令在半路丢失,那么当从服务器向主服务器发送心跳检测命令时,会带上从服务器的当前复制偏移量,主服务器发现从服务器当前的复制偏移量小于自己的复制偏移量,那么就说明有些命令丢失了,主服务器就会在复制积压缓冲区里面找到从服务器缺少的那部分数据,并将这些数据重新发送给从服务器。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cDFykz7K-1632467233907)(C:\Users\Jian\AppData\Roaming\Typora\typora-user-images\image-20210924150529216.png)]

以上就是我们讲的Redis主从架构模式。主从架构模式,通过主从复制的同步操作和命令传播保证了主从数据一致性!同时主从架构实现了读写分离,支持了高并发!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值