15.1 旧版复制功能的实现

同步

命令传播

旧版复制功能的缺陷

15.3 新版复制功能的实现

Redis2.8开始,使用PSYNC命令替代SYNC命令来执行复制时的同步操作

PSYNC命令具有完整重同步和部分重同步两种模式:

  • 完整重同步与SYNC执行步骤基本相同
  • 部分重同步用于处理断线后重复制情况,当从服务器在断线后重新连接服务器时,如果条件允许,主服务器可以将主从服务器连接断开期间执行的写命令发送给从服务器,从服务器只要接收执行这些命令,实现同步

15.4 部分重同步的实现

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

复制偏移量

执行复制的双方——主服务器和从服务器会分别维护一直复制偏移量:

  • 主服务器每次向从服务器传播N个字节的数据时,就将自己的复制偏移量的值上+N
  • 从服务器每次收到主服务器传播来的N个字节的数据时,就将自己的复制偏移量的值+N

复制积压缓冲区

一个向从服务器发送数据的队列,如果发送过程中连接中断,重新连接就可以将队列的内容发送出去,实现重同步,它的大小可以参考每次断开时间*服务器每秒处理的写入请求数

服务器运行ID

从服务器可以通过对主服务器的运行ID进行验证,确认连接的服务器是否为原来的服务器

15.5 PSYNC命令的实现

15.6 复制的实现

步骤1:设置主服务器的地址和端口

从服务器的服务器状态中设置:

struct redisServer{
    //...
    
    
    // 主服务器的地址
    char *masterhost;
    
    // 主服务器的端口
    int masterport;
    
    //...
};

步骤2:建立套接字连接

步骤3:发送PING命令

  • 检查套接字的读写状态
  • 通过发送PING命令可以检查主服务器能否正常处理命令请求
  • 如果主服务器返回一个错误,那么表示主服务器暂时没办法处理从服务器的命令请求,不能继续执行复制工作的后续步骤
  • 如果从服务器读取到“PONG”回复,标识主服务器可以正常处理从服务器发送的命令请求

步骤4:身份验证

如果从服务器设置了masterauth选项,则进行身份验证

步骤5:发送端口信息

从服务器向执行命令REPLCONF listening-port <port-number>主服务器发送端口号

主服务器在客户端状态

struct redisClient{
    //...
    
    // 从服务器的监听端口号
    int slave_listening_port;
    
    //...
};

步骤6:同步

在同步操作执行之后,主从服务器双方都是对方的客户端,它们可以互相向对方发送命令请求,或者返回回复

正因为主服务器成为了从服务器的客户端,所以主服务器才可以通过发送写命令来改变从服务器的数据库状态,不仅同步操作需要用到这一点,这也是主服务器对从服务器执行命令传播操作的基础

步骤7:命令传播

15.7 心跳检测

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

REPLCONF ACK<replication_offset>

对于主服务器有三个作用:

  • 检测主从服务器的网络连接状态
  • 付诸实现min-slaves选项
  • 检测命令失效

检测主从服务器的网络连接状态

INFO replication

lag值显示了从服务器响应的时间,一般这个值在0-1之间

辅助实现min-slaves配置选项

Redis的min-slaces-to-write 和 min-slaces-max-lag 两个选项可以繁殖主服务器在不安全的情况下执行写命令

检测命令丢失