Redis服务器的主从复制机制

在Redis中,客户端可以通过命令SLAVEOF让一个服务器去复制另外一个服务器,我们称呼被复制的服务器称为主服务器,对主服务器进行复制的称之为从服务器。复制后的两个服务器的数据都保持一致。


旧版复制功能


Redis的复制分为同步(sync)和命令传播(command propagate)两个部分:

  • 同步会将主服务器和从服务器的数据保持一致
  • 命令传播则用于主服务器数据发生变动后,让从服务器的数据与主服务器的数据保持一致

其过程用序列图可以表示如下:
在这里插入图片描述

同步

当从服务器向主服务器发送SLAVEOF命令后,同步流程便开始了:

  1. 从服务器向主服务器发送SYNC命令
  2. 主服务器收到SYNC命令后,执行BGSAVE命令并fork一个子进程生成RDB文件然后发送给从服务器。
  3. 从服务器收到RDB文件后,便会加载里面的内容,从而达到主从数据的一致。
命令传播

同步执行完成后主从服务器数据会达到一致的状态,但是当主服务器内部的数据发生变动时就会导致主从数据的不一致。为了解决这个问题,在主服务器收到SYNC命令后,主服务器便会初始化一个缓冲区并保存之后所有执行的写命令,然后将缓冲区的数据发送给从服务器,从服务器会将这些写命令按顺序执行一次,从而保证了数据的一致。

旧版复制的缺陷

主从复制可以分为两种情况:

  • 初次复制:从服务器没有进行过复制操作或者从服务器要复制的主服务器和上次复制的主服务器不一样
  • 断线后复制:当从服务器完成同步后进入命令传播阶段时,与主服务器的网络连接断开。网络连接恢复后,从服务器和主服务器继续进行复制操作。

如果是初次复制,那么上述流程能够符合大多数的需求,但是一旦发生网络连接故障后,上述流程就显得十分累赘了。
在旧版复制中,如果发生了网络连接故障并且恢复连接后,上述流程会重新执行一遍。也就是说,不管主服务器数据发生了多大的变动,从服务器都会再次向主服务器发送SYNC命令并执行RDB文件的生成步骤,这种做法无疑是低效的。所以在Redis 2.8以后推出了PSYNC命令来解决上述问题,也就是新版本的主从复制。

新版复制功能


在Redis 2.8版本以后,PSYNC命令取代了SYNC命令。PSYNC命令具有完整重同步部分重同步两种模式。完整重同步适用于初次复制的情况,其流程和SYNC命令执行的流程基本一致。部分重同步适用于处理断线后复制的情况,当从服务器和主服务器的网络连接恢复正常后,如果在此期间执行的命令没有超出复制积压缓冲区(由主服务器维护),主服务器会将在此期间执行的写命令发送给从服务器,从而达到数据的一致。如果超出了缓冲区,那么会执行完整重同步。

在这里插入图片描述

部分重同步的实现需要以下三个部分:

  • 主服务器和从服务器的复制偏移量
  • 主服务器的复制积压缓冲区
  • 服务器的运行ID
复制偏移量

主服务器和从服务器都会维护一个称之为复制偏移量的变量,当主服务器每次向从服务器发送N个字节时,就会将自己的复制偏移量参数加上N,当从服务器从主服务器读取到N个字节后,也会将自己的复制偏移量参数加上N。通过对比这两者的复制偏移量,就可以知道主从是否处于一致状态。

复制积压缓冲区

主服务器会维护一个固定长度的先进先出队列,默认大小为1M。当主服务器向从服务器发送写命令时,还会将这个写命令复制到这个队列中。所以说,这个队列会保存近期执行的写命令。此外,这个队列还为其中每个字节维护了对应的复制偏移量。

在发生网络故障并且恢复了连接后,如果从服务器偏移量对应的字节仍然存在于主服务器的复制积压缓冲区,那么会执行部分重同步操作,否则就会执行完整重同步操作

服务器运行ID

每个Redis服务器在启动时都会随机产生一个运行ID,这个运行ID由40个十六进制字符构成。当从服务器对主服务器进行复制时,主服务器会将自己的运行ID发送给从服务器并保存。在网络连接故障并且恢复后,从服务器会将这个运行ID发送给主服务器。主服务器收到这个ID后会进行比对,如果这个ID就是当前主服务器的运行ID,那么主服务器就可以尝试进行部分重同步操作,如果不是,就说明之前复制的主服务器并不是当前这个服务器,那么就会进行完整重同步。


维护主从连接的方式


在命令传播阶段中,从服务器会主动以每秒一次的频率向主服务器发送命令:

REPLCONF ACK <replication_offset>

其中<replication_offset>是从服务器的复制偏移量,这个命令可以实现以下几个功能:

  • 检测网络连接状态
    如果主服务器在超过1秒没有收到从服务器发送的REPLCONF ACK命令,那么就可以获知网络发送了问题
  • 检测命令丢失(丢包)
    如果在主服务器向从服务器发送写命令的过程中发生了丢包,那么主服务器收到服务器发送REPLCONF ACK命令时会察觉到自己的偏移量大于从服务器的偏移量,那么主服务器会在复制积压缓冲区找到其丢失的数据并重新发送给从服务器。
  • 实现min-slaves功能
    Redis可以通过配置min-slaves-to-writemin-slaves-max-lag两个选项可以防止主服务器在不安全的情况下执行写命令。
    min-slaves-to-write配置表示最小执行写命令的从服务器数量,即如果从服务器小于这个参数值,那么主服务器是不会执行写命令的。
    min-slaves-max-lag配置表示如果有min-slaves-to-write个从服务器的延迟(单位秒)大于等于其配置值,那么主服务器会拒绝执行写命令。

参考资料

《Redis设计与实现》

发布了117 篇原创文章 · 获赞 96 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/abc123lzf/article/details/89964253
今日推荐