文章目录
- 前言
- 1. 同步以及命令传播
- 1.1 同步
- 1.2 命令传播
- 2. 解决从服务器断线重连
- 2.1 解决方案
- 3. PSYNC命令
- 4. 复制
- 步骤1:设置主服务器的地址和端口
- 步骤2:建立套接字连接 ——其实就是建立TCP连接
- 步骤3:发送PING命令
- 步骤4:身份验证
- 步骤5:发送端口信息
- 步骤6:同步
- 步骤7:命令传播
- 5. 心跳检测
前言
在Redis中,用户可以通过执行SLAVEOF命令或者设置slaveof选 项,让一个服务器去复制(replicate)另一个服务器,我们称呼被复制 的服务器为主服务器(master),而对主服务器进行复制的服务器则被 称为从服务器(slave),如图所示
假设现在有两个redis服务器,地址分别为A:127.0.0.1:6379、B:127.0.0.1:1231,如果A向B发送以下命令:
SLAVEOF 127.0.0.1:6379
那么B服务器将成为A服务器的从服务器,A也会成为B 的主服务器。
进行复制中的主从服务器将保存相同的数据,概念上讲这种现象称为“数据库状态一致”。
1. 同步以及命令传播
1.1 同步
当客户端向从服务器发送SLAVEOF命令,要求从服务器复制主服务器时,从服务器首先需要执行同步操作,也即是,将从服务器的数据库状态更新至主服务器当前所处的数据库状态。
从服务器对主服务器的同步操作需要通过向主服务器发送SYNC
命令来完成,以下是SYNC
命令的执行步骤:
1)从服务器向主服务器发送SYNC
命令
2)收到SYNC
命令的主服务器执行BGSAVE
命令,在后台生成一个RDB文件,并使用一个缓冲区记录从现在开始执行的所有写命令
3)当主服务器的BGSAVE
命令执行完毕时,主服务器会将BGSAVE
命令生成的RDB文件发送给从服务器,从服务器接收并载入这个RDB文件,将自己的数据库状态更新至主服务器执行BGSAVE
命令时的数据库状态
4)主服务器将记录在缓冲区里面的所有写命令发送给从服务器,从服务器执行这些写命令,将自己的数据库状态更新至主服务器数据库当前所处的状态。
1.2 命令传播
从服务器第一次获取到数据以后的操作
为了让主从服务器再次回到一致状态,主服务器需要对从服务器执行命令传播操作:主服务器会将自己执行的写命令,也即是造成主从服务器不一致的那条写命令,发送给从服务器执行,当从服务器执行了相同的写命令之后,主从服务器将再次回到一致状态。
2. 解决从服务器断线重连
为了解决旧版复制功能在处理断线重复制情况时的低效问题Redis从2.8版本开始,使用PSYNC
命令代替SYNC
命令来执行复制时的同步操作。
PSYNC命令具有完整重同步(full resynchronization)和部分重同步(partial resynchronization)两种模式:
- 其中完整重同步用于处理初次复制情况:完整重同步的执行步骤和
SYNC
命令的执行步骤基本一样,它们都是通过让主服务器创建并发送RDB文件,以及向从服务器发送保存在缓冲区里面的写命令来进行同步。 - 而部分重同步则用于处理断线后重复制情况!当从服务器在断线后重新连接主服务器时,如果条件允许,主服务器可以将主从服务器连接断开期间执行的写命令发送给从服务器,从服务器只要接收并执行这些写命令,就可以将数据库更新至主服务器当前所处的状态。
PSYNC命令的部分重同步模式解决了旧版复制功能在处理断线后重复制时出现的低效情况(老版是执行第一次同步步骤)。
2.1 解决方案
部分重同步功能由以下三个部分构成:
-
主服务器的复制偏移量(replication offset)和从服务器的复制偏移量。
-
主服务器的复制积压缓冲区(replication backlog)。
-
服务器的运行ID(run ID)。
主要思想:(重要)
主从服务器都为一个复制偏移量,当主服务器与所有的从服务器复制偏移量相同的时候代表主从数据一致。主服务器每次向从服务器传播N个字节的数据时,就将自己的复制偏移量的值加上N;从服务器每次收到主服务器传播来的N个字节的数据时,就将自己的复制偏移量的值加上N。
同时主服务器会维护一个复制积压缓冲区,是一个有界的FIFO队列,它的拒绝策略并不是满了就丢,而是新来的把最老的顶出去。
主服务和从服务器都有ID,当从服务器第一次slaveOf请求主服务器的会记录下主服务器ID。
当某一个从服务器断线重连的时候会发送一个PSYNC命令,并且附带上主服务器ID以及从服务器的偏移量:
如果主服务器ID和当前的主服务器ID相同:
在主服务器的积压缓冲区中有此偏移量,那么主服务器只需要重新发送缺失的数据(部分重同步);
如果没有,那么会全量重同步。
如果主服务器ID和当前的主服务器ID不同:说明当前主服务器已经变更,需要全量重同步。
3. PSYNC命令
4. 复制
步骤1:设置主服务器的地址和端口
主服务器(127.0.0.1:6379)向从服务器发送以下命令:
SLAVEOF 127.0.0.1 6379
步骤2:建立套接字连接 ——其实就是建立TCP连接
从服务器主动发起连接
如果从服务器创建的套接字能成功连接(connect)到主服务器,那 么从服务器将为这个套接字关联一个专门用于处理复制工作的文件事件 处理器,这个处理器将负责执行后续的复制工作,比如接收RDB文件, 以及接收主服务器传播来的写命令,诸如此类。
而主服务器在接受(accept)从服务器的套接字连接之后,将为该 套接字创建相应的客户端状态,并将从服务器看作是一个连接到主服务 器的客户端来对待,这时从服务器将同时具有服务器(server)和客户 端(client)两个身份:从服务器可以向主服务器发送命令请求,而主 服务器则会向从服务器返回命令回复。
步骤3:发送PING命令
注意是从 —> 主
ping的作用:
-
虽然主从服务器成功建立起了套接字连接,但双方并未使用该套 接字进行过任何通信,通过发送PING命令可以检查套接字的读写状态 是否正常。
-
因为复制工作接下来的几个步骤都必须在主服务器可以正常处理 命令请求的状态下才能进行,通过发送PING命令可以检查主服务器能否正常处理命令请求
步骤4:身份验证
步骤5:发送端口信息
目前没什么用
步骤6:同步
在这一步,从服务器将向主服务器发送PSYNC
命令,执行同步操作,并将自己的数据库更新至主服务器数据库当前所处的状态。
值得一提的是,在同步操作执行之前,只有从服务器是主服务器的客户端,但是在执行同步操作之后,主服务器也会成为从服务器的容户端:
- 如果
PSYNC
命令执行的是完整重同步操作,那么主服务器需要成为从服务器的客户端,才能将保存在缓冲区里面的写命令发送给从服务器执行。 - 如果PSYNC命令执行的是部分重同步操作,那么主服务器需要成为从服务器的客户端,才能向从服务器发送保存在复制积压缓冲区里面的写命令。
因此,在同步操作执行之后,主从服务器双方都是对方的客户端,它们可以互相向对方发送命令请求,或者互相向对方返回命令回复。正因为主服务器成为了从服务器的客户端,所以主服务器才可以通过发送写命令来改变从服务器的数据库状态,不仅同步操作需要用到这一点,这也是主服务器对从服务器执行命令传播操作的基础。
步骤7:命令传播
当完成了同步之后,主从服务器就会进入命令传播阶段,这时主服务器只要一直将自己执行的写命令发送给从服务器,而从服务器只要一直接收并执行主服务器发来的写命令,就可以保证主从服务器一直保持一致了。
5. 心跳检测
发送REPLCONF ACK
命令对于主从服务器有三个作用:
-
检测主从服务器的网络连接状态。
-
辅助实现min-slaves选项。
-
检测命令丢失。