Redis的复制功能分为同步(sync)和命令传播(command propagate)两个操作。
同步
同步操作用于将从服务器的数据库状态更新至主服务器当前所处的数据库状态。
1. 旧版本的执行步骤
- 从服务器向主服务器发送SYNC命令
- 主服务器执行BGSAVE命令,生成RDB文件,并使用一个缓冲区记录从现在开始执行的所有写命令
- 当主服务器执行完BGSAVE命令后,主服务器将RDB文件发送给从服务器,从服务器载入RDB文件
- 主服务器将记录在缓冲区里的写命令发送给从服务器,从服务器执行后更新至主服务器数据库当前的状态
2. 旧版本存在的问题
断线后重复制效率低,有大量重复的数据不需要同步
3. 新版本的复制功能
同步操作从SYNC命令切换成PSYNC命令,PSYNC命令支持完全重同步(full resynchronization)和部分重同步(partial resynchronization)两种模式。
- 完全重同步:用来处理初次复制的情况
- 部分重同步:用来处理断线后重复制的情况,由3部分构成:
- 主服务的复制偏移量(replication offset)和从服务器的复制偏移量
- 主服务器的复制积压缓冲区(replication backlog),维护一个固定长度的FIFO队列
- 服务器的运行ID(run ID)
在进行主从同步时,以下情况进行完全重同步,其余情况采用部分重同步。
- 从服务器从来没有同步过主服务器的任何数据
- 从服务器持用的run ID与主服务器不一致(主服务器换了)
- 从服务器的offset不在复制积压缓冲区中
命令传播
命令传播操作用于在主服务器的数据库状态修改,导致主从服务器的数据库状态出现不一致时,让主从服务器的数据库状态重新回到一致状态。
在命令传播阶段,从服务器会默认以每秒一次的频率,向主服务器发送命令,发送的REPLCONF ACK命令对主从服务器有三个作用:
- 检测主服务器的网络连接状态
- 辅助实现min-slaves选项,Redis的
min-slaves-to-write
和min-slaves-max-log
两个选项可以防止主服务器在不安全的情况下执行写命令 - 检测命令丢失,通过检测主从服务器的
offset
来确定主从服务器之间数据是否一致。如果不一致会从复制积压缓冲区中将数据补发给从服务器,如果复制积压缓冲区中没有对应的offset
,需要进行完全重同步
复制方案的实现
通过向主服务器发送SLAVEOF命令,我们可以让一个从服务器去复制一个主服务器的数据,具体实现步骤如下:
- 设置主服务器的地址和端口
- 主从服务器建立套接字连接
- 发送PING命令检测主从服务器之间通讯是否正常
- 身份验证
- 发送从服务器的监听端口
- 执行同步
- 命令传播