旧版复制功能

  • 分为同步(sync)和命令传播(command propagate)两个操作:
    • 同步:从主机同步到从机
    • 命令传播:主机将命令转发给从机,从机执行命令,从而实现数据同步

      旧版同步步骤

  1. 客户端向准从机发送 SLAVEOF 命令,使其变成某台机器的从机
  2. 从机向主机发送SYNC命令
  3. 主机收到SYNC命令,并执行BGSAVE命令,在后台生成一个RDB文件,并使用一个缓冲区记录此刻之后的所有写命令
  4. 主机BGSAVE执行完毕,将RDB发送给从机
  5. 从机接收并载入RDB文件,更新数据
  6. 主机把缓冲区里的命令发送给从机,从机执行命令更新数据 主从复制原理 - 图1

    旧版命令传播

  7. 客户端向主机发送写命令

  8. 主机执行写命令
  9. 主机向从机发送写命令
  10. 从机执行写命令 主从复制原理 - 图2

    旧版复制功能的缺陷

  • 旧版设计中,断线重连后,需要重新发送 SYNC ,重新进行全量复制

    新版同步步骤

    从2.8开始,Redis使用PSYNC代替SYNC进行同步。PSYNC具有完整重同步(full resynchronization)、部分重同步(partial resynchronization)两种模式:

  • 完整重同步用于初次同步的情况:操作步骤和SYNC命令一样

  • 部分重同步用于断线后重新复制的情况:从机可以从主机获取断线期间的写命令,并重新执行 主从复制原理 - 图3

    部分重同步的实现

    重点:

  • 主机和从机的复制偏移量(replication offset)

  • 主机的复制积压缓冲区(replication backlog)
  • 服务器的运行ID(run ID)

    复制偏移量

  • 主机偏移量:每同步一条命令,就在偏移量上加上这条命令的字节数。同一条命令不重复计数

  • 从机偏移量:收到的字节数,每收到一条命令就在偏移量上加上命令的字节数
  • 把主机上所有的写命令排成一个字符序列,偏移量其实就是指到这个序列的哪个位置了
  • 偏移量一致,则数据一致。偏移量不一致,从机就应该发送 PSYNC 命令同步数据了

    复制积压缓冲区

  • 缓冲区实现:固定长度的先进先出队列

  • 主机进行命令传播时,把命令发送给从机的同时,还回把命令写入“复制积压缓冲区”
  • 当从机断线重连后,主机会根据偏移量来决定使用哪种同步机制
    • 从机offset + 1的数据仍在缓冲区中:执行部分重同步的操作
    • 从机offset + 1的数据已经不在缓冲区中:执行完整重同步操作
  • 缓冲区大小:默认1MB。高并发写操作时,需要调大缓冲区,避免部分重同步操作机制失效 主从复制原理 - 图4

    服务器运行ID

  • 每个redis进程都有自己的运行ID

  • 在进程启动时生成,是一个长度40的十六进制字符串
  • 根据 ip:port 的方式区分redis进程是不可靠的。如果redis进程在极短的时间内重启了,使用者只根据 ip:port 是无法识别出redis的重启行为的
  • runID如果不同, 那肯定是要进行完整重同步的

    PSYNC的具体实现

  • 命令:PSYNC

  • 初次同步:PSYNC ? -1
  • 再次同步:PSYNC 20549aa994fcd395a1330f05876e552981a5ad12 1536
  • 命令回复:
    • +FULLRESYNC :执行完整重同步。offset是指RDB对应的初始offset
    • +CONTINUE:执行部分重同步。从机接下来等待主机发送写命令就好
    • -ERR:主机版本低于2.8从而无法识别命令。从机改为使用SYNC命令进行同步

主机回复逻辑: 主从复制原理 - 图5

复制的步骤

当客户端向从机发送SLAVEOF命令时:

  • 客户端发送: SLAVEOF 192.168.110.130 6379
  • 第一步,记录端口地址:从机将 ip:port 记录到masterhost和masterport中去,然后马上返回OK
  • 第二步,建立连接:从机主动connect主机
  • 第三步,发送PING:connect成功,从机马上发送一个PING请求。
    • 如果从机收到错误响应,或者主机响应超时,从机就会断开重连
    • 如果从机收到PONG响应,就进行下一个步骤
  • 第四步,身份验证:如果从机设置了masterauth选项,从机就会向主机发送一条AUTH命令,没有设置则不发。主机可能有如下响应:
    • invalid password:密码错误
    • no password is set:主机没有设置密码,但从机发送了AUTH命令
    • NOAUTH:主机设置了密码,但从机没有发送AUTH命令
    • 通过:两边都没设置密码,或者密码认证通过
  • 第五步,发送端口信息:从机执行 REPLCONF listening-port <port> ,向主机发送自己的监听端口号。这个端口号目前只用作INFO命令显示从机信息
  • 第六步,同步:从机向主机发送PSYNC命令
  • 第七步,命令传播:主机持续向从机发送最新的写命令

    心跳检测机制

  • 从机每隔一秒向主机发送一次 REPLCONF ACK <replication_offset> replication_offset 是从机当前的复制偏移量

  • 心跳的作用:

    • 检测主从服务器网络连接状态
    • 辅助实现 min-slaves 选项
    • 防止命令丢失

      检测网络状态

      主机可通过记录REPLCONF ACK命令,来标识最后一次确认从机存活的时间。这个时间可以使用INFO replication看到

      辅助实现min-slaves选项

  • min-slaves-max-lag :最大延迟时间。主机记录了从机最后一次心跳时间,自然也能推算出来是否超过了最大延迟时间。

  • min-slaves-to-write :最小可写从机个数。对于超过最大延迟时间的从机,就可以认为是不可写的了。

    防止命令丢失

  • 当写命令丢失时,从机发来的 replication_offset 就会小于主机的复制偏移量。主机这时就会补发缺失的命令

  • 这个行为和部分重复制有些类似,但是部分重复制是在网络连接断开的情况下,而REPLCONF是在网络连接没有断开的情况下