在Redis中,用户可以通过执行SLAVEOF命令,让一个服务器去复制(replicate)另一个服务器,那么主动复制的就是从服务器,被复制的就是主服务器。
老版本
Redis的复制功能分为同步(sync)和命令传播(command propagate)两个操作:
❑同步操作用于将从服务器的数据库状态更新至主服务器当前所处的数据库状态。
❑命令传播操作则用于在主服务器的数据库状态被修改,导致主从服务器的数据库状态出现不一致时,让主从服务器的数据库重新回到一致状态。
同步(sync)
同步操作是从服务器向主服务器发送sync命令来完成的,具体步骤如下:
(1)从服务器向主服务器发送SYNC命令
(2)收到命令的主服务器执行BGSAVE命令,在后台生成一个RDB文件,同时创建一个缓冲区来记录这期间所有的写命令
(3)RDB文件生成后,从服务器载入RDB文件,之后主服务器将缓冲区中的命令发送给从服务器,从服务器执行这些命令后就和主服务器的数据保持一致。
SYNC的缺陷
当从服务器断线重连之后,向主服务器发送SYNC命令,主服务器会再生成RDB文件,该RDB文件包含了断线之前的数据,但是从服务器只需要断线之后到重连这段时间丢失的数据,这就造成了资源的浪费。
命令传播
当主服务器执行了一条更新命令后,它会将该命令发送给从服务器,从服务器执行该命令来保持数据一致性。
在命令传播阶段,有一个心跳检测,从服务器默认会以每秒一次的频率,向主服务器发送带有复制偏移量的ACK命令
发送REPLCONF ACK命令对于主从服务器有三个作用:
❑检测主从服务器的网络连接状态。
如果主服务器超过一秒没有收到从服务器发来的ACK命令,那么它就知道连接出现了问题。
❑辅助实现min-slaves选项。
❑检测命令丢失。
由于网络原因,主服务器传播给从服务器的写命令可能半路丢失,那么当从服务器向主服务器发送ACK命令时,主服务器就可以察觉到从服务器的复制偏移量小于自己的复制偏移量,那么它就会通过该复制偏移量在缓冲区中找到相应的数据发送给从服务器。
新版本
使用PSYNC命令代替SYNC命令来执行复制时的同步操作。
PSYNC的完整重同步和SYNC命令的执行流程一样。
PSYNC命令和SYNC命令的不同之处在于它拥有部分同步功能,当从服务器重连之后,发送PSYNC命令,主服务器可以将主从服务器连接断开期间执行的写命令发送给从服务器,从服务器只要接收并执行这些写命令,就可以将数据库更新至主服务器当前所处的状态。
部分同步功能的实现
部分重同步功能由以下三个部分构成:
❑主服务器的复制偏移量(replication offset)和从服务器的复制偏移量。
主服务器每次向从服务器发送N个字节的数据时,就将自己的偏移量加上N,从服务器每次接受N个字节的数据时,就将自己的偏移量加N。那么通过对比主从服务器的偏移量就可以知道数据是否一致。
❑主服务器的复制积压缓冲区(replication backlog)。
该缓冲区是主服务器维护的一个固定大小的先进先出队列,该缓冲区中存储了最近一段时间的写命令,同时缓冲区中的每个字节都标有偏移量,当从服务器重连发送PSYNC命令,并将自己的复制偏移量发送给主服务器,主服务器通过判断该偏移量+1的数据是否在缓冲区内来做出不同的反应:
- 如果offset+1在缓冲区内,那么就将缓冲区内相应命令发送给从服务器,执行部分同步操作。
- 如果offset+1不在缓冲区内,那么就执行完整同步操作。
❑服务器的运行ID(run ID)。
主服务器和从服务器都有自己的运行ID,当主从服务器进行初次复制时,从服务器就会将与其向连的主服务器的ID保存起来,当从服务器与主服务器重连时,它会先通过ID判断这个服务器和上次的服务器是否是同一个服务器,如果是的话就执行部分同步操作,如果不是就执行完成同步操作。
文章参考《Redis设计与实现》