Redis的主从复制

必备知识:https://blog.csdn.net/sinat_32366329/article/details/81160282

旧版复制功能的实现

Redis的复制功能可以分为 同步命令传播 两个操作:

同步 操作用于将从服务器的数据库状态更新至主服务器当前所处的状态。

命令传播 操作则用于在主服务器的数据库状态被修改,导致主从服务器的数据库状态不一致时,让主从服务器的数据库重新回到一致状态。

同步

当客户端向从服务器发送SLAVEOF命令,要求从服务器复制主服务器时,从服务器首先要执行同步操作,即将从服务器的数据库状态更新至主服务器当前所处的数据库状态。

同步过程步骤如下:

  1. 从服务器向主服务器发送SYNC命令。
  2. 收到SYNC命令的主服务器执行BGSAVE命令,在后台生成一个RDB文件,并使用一个缓冲区记录从现在开始执行的所有写命令。
  3. 当主服务器的BGSAVE命令执行完毕,主服务器将生成的RDB文件发送给从服务器,从服务器接收并加载这个RDB文件,将自己的数据库状态更新至主服务器执行BGSAVE命令是的数据库状态。
  4. 主服务器将记录在缓冲区里面的所有写命令发送给从服务器,从服务器执行这些写命令,将自己的数据库状态更新至主服务器当前所处的状态。

同步图解过程

命令传播

在同步操作完毕后,主从服务器两者的数据库状态达到一致,但是如果客户端发送写命令给主服务器时,将导致主从服务器状态不一致。

为了让主从服务器数据一致,主服务器需要对从服务器执行命令传播操作:主服务器会将自己执行的那条写命令,发送给从服务器执行,当从服务器执行了该写命令后,主从服务器将再次回到一致状态。

旧版复制功能的缺陷2.8以前

在Redis中,从服务器对主服务器的复制可以分为以下两种情况:

  1. 初次复制:从服务器以前没有复制过任何主服务器。或者上次复制的主服务器和这一次不是同一个主服务器。
  2. 短线后重新复制:处于命令传播阶段的主服务器因为网络原因而中断复制,但从服务器通过自动重现连接上了主服务器,并继续复制主服务器。

图解过程如下

严重缺陷

  1. 主服务器在时间T0到T10086过程中一直处于一致状态。这两个服务器的数据是一样的。
  2. 从服务器断开重连后,只需要主服务器的K10087,K10088,K10089三个命令即可,但是主服务器却返回了一个新的RDB文件,如果RDB文件很大,必将导致严重的内存问题。

新版复制功能的实现2.8开始

为了解决旧版的问题,Redis2.8以后引入了PSYNC代替SYNC命令执行复制时的同步操作。

PSYNC命令具有完全同步和部分重同步功能。

完全同步和旧版的同步是一样的。

部分重同步主要是用于断线后的重复制情况:当从服务器断开重新连接后,如果条件允许,主服务器将断开期间的写命令发给从服务器,从服务器执行断开期间的写命令完成同步,将数据库更新到和主服务器一致。

部分重同步的实现

  1. 主服务器的复制偏移量和从服务器的复制偏移量。
  2. 主服务器的复制积压缓冲区(队列,默认1MB)。
  3. 服务器的允许ID。

主服务器和从服务器都会维护一个复制偏移量,主要是用户对比复制的执行结果。例如主从服务器的复制偏移量均为1000,当主服务器完成了3个写命令后,主服务器偏移量为1003,这时候将3个命令给从服务器执行,从服务器执行完毕,复制偏移量也为1003。

如果主从服务器的数据是一致的,那么他们的偏移量也是一致的。

复制积压缓冲区,在主服务器将写命令给从服务器后,还会写入到复制积压缓冲区,如果执行到了偏移量为1003的时候,从服务器A断开,主服务器继续执行了7个写入命令,这时候主服务器的偏移量为1100,A服务器连接上,请求复制主服务器,这时候主服务器会分情况处理。

1)主服务器不是A从服务器之前复制的主服务器(根据服务器ID判断),执行完全同步。

2)发现A从服务器之前复制的是自己。根据A从服务器的偏移量去复制积压缓冲区中看1004-1100命令是否依然存在,如果存在将1004-1100偏移量的命令返回给A从服务器执行。如果不存在,只能执行完全同步恢复数据一致了。