在Redis中,用户可以通过SALVEOF命令或者设置配置文件中salveof选项,让一个服务器去复制另一个服务器,被复制的服务器成为主服务器,对主服务器进行复制的服务器称为从服务器。
一、旧版复制功能的实现
Redis的复制功能分为同步和命令传播两个操作
a、同步:同步操作用于将服务器的数据库状态更新至主服务器当前所处的状态
b、命令传播:命令传播操作则用于在主服务器的数据库状态被修改,导致主从服务器的数据库状态出现不一致时,让主从服务器的数据库状态回到一致状态
①同步:
当客户端向从服务器发送SALVEOF命令,要求从服务器复制主服务器时,从服务器首先执行同步操作 ,也即是将从服务器的数据库状态更新至主服务器当前所处的数据库状态
从服务器对主服务器的同步操作需要通过向主服务器发送SYNC命令来完成,执行步骤如下
1、从服务器向主服务器发送SYNC命令
2、收到SYNC命令的主服务器执行BGSAVE命令,在后台生成一个RDB文件,并使用一个缓冲区记录从现在开始执行的所有写命令
3、当主服务器的BGSAVE命令完成时,主服务器会将这个RDB文件发送给从服务器,从服务器接收并载入这个RDB文件,将自己的数据库状态更新至主服务器执行BGSAVE命令时的数据库状态
4、主服务器将记录在缓冲区里面的所有写命令发送给从服务器,从服务器执行这些写命令,将自己的数据库状态更新至主服务器当前所处的数据库状态。
抠张图
②命令传播:
在同步操作执行完毕之后,主从服务器两者的数据库状态将达到一致状态,但这种一致并不会是一成不变的,每当主服务器执行客户端发送的写命令时,主从服务器的数据库就有可能被修改,并导致主从服务器状态不再一致。
为了让主从服务器再次回到一致状态,主服务器需要将对从服务器执行命令传播操作:主服务器会将自己执行的写命令,发送给从服务器执行,当从服务器执行命令之后,主从服务器将再次回到一致状态。
抠张图
③旧版复制功能的缺陷:
a、初次复制:从服务器以前没有复制过任何主服务器,或者从服务器当前要复制的主服务器与上次复制的主服务器不同
b、断线后重复制:处于命令传播阶段的主从服务器因为网络原因而中断了复制,但从服务器通过自动重连重新连接上了主服务器,并继续复制主服务器。
在这里可以看到,对于初次复制,旧版复制功能能够很好的完成任务,但对于断线后重连复制来说,效率非常低,虽然也能完成任务。
二、新版复制功能的实现
新版复制功能使用PSYNC来代替SYNC命令来执行复制时的同步操作
PSYNC命令具有完整重同步和部分重同步两种模式:
a、完整重同步和SYNC命令的执行步骤基本一样,都是主服务器创建并发送RDB文件,以及向从服务器发送保存在缓冲区里面的写命令来进行同步
b、部分重同步则用于断线后重复制情况:当从服务器在断线后重新连接主服务器时,如果条件允许,主服务器可以将主从服务器连接断开期间执行的写命令发送给从服务器,从服务器只要执行这些命令,便可以将数据库更新至主服务器当前所处的数据库状态。
三、部分重同步的实现
部分重同步有三个部分构成:
a、主服务器的复制偏移量和从服务器的复制偏移量
b、主服务器的复制积压缓冲区
c、服务器的运行ID
①复制偏移量
执行复制的双方---主服务器和从服务器会分别维护一个复制偏移量
a、主服务器每次向从服务器传播N个字节的数据时,就将自己的复制偏移量的值加N
b、从服务器每次收到主服务器传播来的N个字节的数据时,就将自己的复制偏移量的值加N
通过对比主从服务器的复制偏移量,程序很容易的知道主从服务器是否处于一致状态:
a、如果主从服务器处于一致状态,那么主从服务器两者的偏移量总是相同的
b、相反,如果主从服务器的复制偏移量不同,那么说明主从服务器并没有处于一致状态
我们看一个问题
当主服务器要向从服务器发送33字节的数据之前,从服务器A断线了,那么只有从服务器B和C能收到,在这之后,B和C的复制偏移量加33,而断线的服务器仍然是10086,当从服务器A上线时,从服务器将给主服务器发送PSYNC命令,告诉主服务器自己的复制偏移量为10086,那么主服务器该进行完整重复制还是部分重复制呢?这就和复制积压缓冲区有关
②复制积压缓冲区
复制积压缓冲区是由主服务器维护的一个固定长度的先进先出的队列,默认为1MB。
当主服务器进行命令传播时,它不仅会将写命令发送给所有从服务器,还会将写命令入队到复制积压缓冲区
抠张图
因此,主服务器的复制积压缓冲区里面保存着一部分最近传播的写命令,并且复制积压缓冲区会为队列中的每个字节记录相应的复制偏移量
抠张图
当从服务器重新连上主服务器时,从服务器会通过PSYNC命令将自己的复制偏移量发送给主服务器,主服务器会根据这个复制偏移量来决定对从服务器执行何种同步操作:
a、如果从服务器的复制偏移量offset之后的数据仍然存在与复制积压缓冲区里面,那么主服务器将对从服务器执行部分重同步
b、如果从服务器的复制偏移量offset之后的数据已经不存在与复制积压缓冲区,那么主服务器将对从服务器执行完整重同步
③服务器运行ID
除了复制偏移量和复制积压缓冲区之外,实现部分重同步还需要用到服务器运行ID
a、每个Redis服务器,不论主从,都会有自己的运行ID
b、运行ID在服务器启动时自动生成,有40个随机的十六进制字符组成
当从服务器对主服务器进行初次复制时,主服务器会将自己的运行ID发送给从服务器,而从服务器则会将这个运行ID保存起来
当从服务器断线重连时,从服务器将当前连接的主服务器发送之前保存的运行ID
a、如果从服务器保存的运行ID和当前连接的主服务器运行ID相同,那么主服务器可以继续尝试执行部分重同步
b、相反的,如果从服务器保存的运行ID和当前连接的主服务器运行ID不同,则主服务器将对从服务器执行完整重同步