Redis复制原理

一:旧版复制 (2.8版以前)

1、分2个步骤:同步 和 命令传播

  1. sync 同步

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

  1. command propagate 命令传播

当主服务器的数据库状态被修改,导致主从服务器状态不一致,让主从服务器的数据库状态回到一致状态

1.1 同步-从(slave)服务器向主服务器发送SYNC命令步骤:

  1. 从服务器向主服务器发送SYNC命令
  2. 主服务器收到SYNC命令后, 执行BGSAVE命令,生成RDB文件,
  3. 主服务器此时使用一个缓冲区记录主服务器执行的所有写命令
  4. 主服务器的BGSAVE命令执行完毕,主服务器将生成的RDB文件发送给从服务器
  5. 从服务器收到RDB文件,将自己的数据库状态更新至主服务器状态
  6. 主服务器将记录在缓冲区的写命令发送给从服务器,从服务器执行这些写命令,将从服务器更新至主服务器状态

1.2 命令传播

在同步完成后,主从服务器两者的数据库达到了一致状态。 这种状态并不是一直不变的,当主服务器有写入或者删除命令时候,就会导致主从不一致。

为了让主从服务器再次回到一致状态,主服务器需要对从服务器执行命令广播操作: 主服务器将自己的写命令,发送给从服务器执行。


## 二、旧版复制功能的缺点 在Redis复制中,有2种情况:
  • 初次复制:从服务器以前没有复制过任何主服务器,
  • 断线后重复制:处于命令传播阶段的主从服务器因为网络原因中断,从服务通过自动重连方式重新连上主服务器,继续进行复制

初次完整的复制,旧版没啥问题;但是断线后重连,就会有问题了。

缺点:
断线后的重复制,旧版还是会用SYNC的发送RDB文件给从服务器,这样就包含了很多以前已经复制过的内容了,因此很浪费效率,我们只需要复制中断期间的这些数据就可以了。
新版(2.8以后)改进了这个部分重复制功能


## 三:新版复制功能(2.8版以后) > 2.8 版以后使用PSYNC命令代替SYNC命令执行同步复制的操作
### 1、PSYNC命令具有完整同步和部分重同步的功能
  • 完整重同步:用于初次同步,和SYNC命令执行的步骤差不多,主服务器发送RDB文件和缓冲区保留写命令
  • 部分重同步:从服务断线后重新连上主服务器,主服务器可以将从服务器连接断开这都时间执行的写命令发送

给从服务器,从而让主从服务器状态达到一致。新版解决了旧版重复制低效的问题。

### 2、部分重同步的实现

2.1 主要有3个部分构成:

  • 主服务器的复制偏移量(replacation offset)和从服务器的复制偏移量
  • 主服务器的复制积压缓冲区(replication backlog)
  • 服务器运行的ID(run ID)

#### 2.1.1 复制偏移量 > 主从服务器分别会维护一个复制偏移量
  • 主服务器每次向从服务器传播N个字节数据时,就将自己复制偏移量的值加上N
  • 从服务器每次收到主服务器传播来的N个字节数据时,就将自己的复制偏移量的值加上N

eg:
主服务器offset=10086  
从服务器A offset=10086
从服务器B offset=10086

主服务器向从服务器A B传播33个字节后,这时主从服务器的偏移量为
主服务器offset=10119
从服务器A offset=10086+33 -> 10119
从服务器B offset=10086+33  -> 10119

通过上面我们可以看出,对比主从服务器的偏移量,程序就可以知道主从服务器状态是否一致:

  • 如果主从服务器处于一致状态,那么主从服务器的偏移量总是相同的
  • 如果偏移量不同,那么主从服务器的状态并不一致

#### 2.1.2 复制积压缓冲区 **为什么有复制积压缓冲区?**
上面的例子,如果同步时候从服务器A断线了,B复制成功了。过一会后,从服务器A又连上了主服务器。从服务器
A向主服务器发送PSYNC命令,报告从服务器A当前的复制偏移量,那么这时,主服务器应该对从服务器执行完整重
同步还是部分重同步? 如果执行部分重同步,主服务器又如何补偿从服务器A断线期间丢失的部分数据? 这个就和
复制积压缓冲区有关了。

复制积压缓冲区:由主服务器维护的一个固定长度的先进先出(FIFO)队列,默认大小1MB

当主服务器进行命令传播时,它不仅会把写命令发送给所有从服务器,还会将写命令写入复制积压缓冲区。
因此,主服务器的复制积压缓冲区会保存一部分最近传播的写命令,而且还会为队列的每个字节记录相应的复制偏移量。

**什么时候部分重同步,什么时候完整重同步?**
当从服务器连上主服务器时,从服务器通过PSYNC将自己的复制偏移量offset发送给主服务器,主服务器会根据这个复制偏移量来决定是何种同步模式:
1、如果offset偏移量之后的数据**仍然在复制积压缓冲区**,那么执行**部分重同步操作**
2、如果offset偏移量之后的数据已经**不存在复制积压缓冲区**,那么执行**完整的重同步操作**

#### 2.1.3 服务器运行ID(run ID) 除了复制偏移量和复制积压缓冲区,实现部分重同步还需要用到服务器运行ID
  • 每个Redis服务器都有自己运行的ID
  • 当重服务器进行初次复制时,主服务器会将自己的服务器ID传递给从服务器,从服务器会保存这个ID

从服务器断线重连时,连上主服务器,从服务器会将之前保存的主服务器ID发送给主服务器

  • 如果从服务器保存的主服务器ID和当前连接的主服务器运行的ID相同,说明从服务器断线之前连接的就是这个主服务器,主服务器可以继续尝试部分重同步
  • 相反,如果从服务器保存运行的ID和当前连接的主服务器运行ID不相同,说明从服务器断线之前复制的主主服务器并不是当前连接的这个主服务器,主服务器将执行完整的重同步

参考:《redis设计与实现》

原文地址:https://www.cnblogs.com/jiujuan/p/11278486.html