-
- 复制偏移量
-
复制积压缓冲区
-
- 拓展固定长度队列
-
调整复制积压缓冲区的大小
-
服务器运行ID
[](()复制
在Redis中,我们可以通过执行SLAVEOF命令或者设置slaveof选项(如果有主服务器有密码,还需要设置masterauth选项,最好把日志功能打开,即设置logfile选项,失败的话,可以从日志中看),让一个服务器去复制另一个服务器,被复制的服务器称为主服务器,而对主服务器进行复制的服务器称为从服务器
举个栗子
slaveof 127.0.0.1 6379
执行上面的命令后,本服务器就会成为127.0.0.1 6379的从服务器
进行复制中的主从服务器双方的数据库将保存相同的数据,这种现象称为主从一致
[](()旧版复制功能的实现
Redis的复制功能分为同步(sync/fsync)和命令传播(command propagate)两个操作。
-
同步操作用于将从服务器的数据库状态更新至主服务器当前所处的数据库状态(从服务器执行)
-
命令传播操作则用于在主服务器的数据库状态被修改后(前面已经完成同步操作),导致发生了主从不一致的现象时,让主从服务器的数据库重新回到一致状态。(主服务器执行)
[](()同步
当客户端向从服务器发送SLAVEOF命令,要求从服务器复制主服务器时,从服务器首先会需要去执行同步操作,将自己的状态更新成与主服务器状态一致。(此时从服务器只能读而不可以写了)
从服务器对主服务器的同步操作,*需要通过向主服务器发送SYNC命令来完成 《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》无偿开源 威信搜索公众号【编程进阶路】 *,具体的执行步骤如下所示
-
从服务器向主服务器发送SYNC命令
-
主服务器接收到从服务器发送的SYNC命令,此时会进行一个BGSAVE命令,在后台生成一个RDB文件,并且会使用一个缓冲区记录从现在开始执行的所有写命令
-
当主服务器完成BGSAVE命令后,主服务器会将生成的RDB文件发送给从服务器,从服务器会接受并载入这个RDB文件,将自己的数据库状态更新至主服务器执行BGSAVE命令时的数据库状态(注意此时从服务器里面原有的数据就会消失不见)
-
主服务完成BGSAVE命令后,还会将记录在缓冲区里面的所有写命令发送给从服务器,从服务器执行这些写命令,再将自己的数据库状态更新至主服务器数据库当前的状态(避免了执行BGSAVE时数据的丢失)
上图可以看到,从服务器的onlymehave字符串对象不见了
[](()命令传播
同步操作执行完后,从服务器的状态跟主服务器一致了,但这种一致并不是永远保持的,每当主服务器执行客户端发送的写命令时,主服务器的数据库就可能被修改,但从服务器并没有修改,主从又不一致了。
为了让主从再回到一致状态,主服务器就需要对从服务器执行命令传播操作
命令传播操作即:主服务器将自己新执行的写命令,发送给从服务器,从服务器执行发送过来的命令,这样主从状态又一致了。
[](()旧版复制功能的缺陷
旧版复制功能的复制可以分为下面两种情况
-
初次复制:从服务器在复制以前没有复制过任何主服务器,或者从服务器要复制新的主服务器
-
断线后重复制:从服务器已经完成同步,处于命令传播状态,在接受主服务器新执行的命令,但此时从服务器由于网络原因与主服务器断开了连接,需要进行重新连接,连接后要进行重新复制
对于第一种情况,旧版是做的不错的。
关键在于第二种情况,断线后重新复制是很浪费资源的(因为重新连接后无法判断此时主从状态是否一致,所以只能重新同步,完成一致),比如说,你主从服务器已经完成同步,已经有1万个键同步好了,但此时你从服务器宕机了,重启后,又去进行同步,又要去复制1万个键,包括宕机时主服务器插入的新键,但实际上,重连的从服务器只需要复制宕机时主服务器插入的新键即可。
总结来说,就是Sync命令会十分耗费资源,因为每次执行Sync,主从服务器要进行下列的步骤
-
主服务器要执行BGSAVE命令生成RDB文件,耗费主服务器的CPU、内存和磁盘IO资源
-
主服务器执行完BGSAVE之后,还要发送RDB文件给从服务器,耗费网络资源
-
从服务器接受主服务器发送的RDB文件,然后进行载入RDB文件,此时耗费CPU去读取,而且载入RDB文件时,是会发生阻塞的,从服务器会停止对外提供读服务。
所以,要在真正有必要的时候,才去执行Sync命令
[](()新版复制功能的实现
新版复制功能其实是为了解决旧版的断线重复制的问题(为了解决主从状态是否一致问题),从2.8版本开始,使用Psync命令代替了Sync命令(即从服务器不再发送Sync命令,取而代之的是Psync命令)
Psync命令具有完整重同步和部分重同步两种模式
-
完整重同步是用于初次复制,也就是第一次同步的情况,完整重同步的执行步骤和Sync基本是一样的,同样主服务器进行BGSAVE,然后发送RDB,缓冲池记录新的写命令,从服务器接受RDB,进行载入,载入后接受主服务器发送缓冲池新的写命令,然后执行新的写命令,完成整个同步操作
-
部分重同步则是针对于断线后重复制情况的,当从服务器在断线后重新连接主服务器时,如果条件允许,主服务器可以将从服务器连接断开期间执行的写命令发送给从服务器,而不是重新复制,从服务器接收并去执行这些命令,这也就解决了全部重新复制的问题
部分重同步的过程如下图所示
[](()部分重同步的实现
完整重同步的实现跟Sync差不多,这里就不重复了,下面说一下部分重同步的实现
部分重同步功能由以下三个部分构成
-
主服务器的复制偏移量和从服务器的复制偏移量
-
主服务器的复制积压缓冲区
-
服务器的运行ID
[](()复制偏移量
执行复制的双方,也就是主从服务器,都要分别去维护一个复制偏移量(初始为0)
-
主服务器每次向从服务器发送数据时,要统计发送了多少字节,然后将自己的复制偏移量加上N
-
从服务器每次从主服务器接受数据时,也要统计接受了多少字节,然后将自己的复制偏移量加上N
这样就可以通过比对主从的复制偏移量,就可以判断主从状态是否一致了
-
如果主从状态一致,那么主从服务器两者的偏移量总是相同的
-
如果两者的偏移量不相同,说明了主从状态并不一致
[](()复制积压缓冲区
通过复制偏移量,我们可以判断主从服务器状态是否一致了,但是真正要去执行完整重同步还是部分重同步,就要由复制积压缓冲区去决定了
复制积压缓冲区是由主服务器维护的一个固定长度、先进先出的队列,默认大小为1MB