Redis 主从同步

本文将介绍 Redis 中主从模式时主机和从机之间进行数据同步的做法。

一、初次同步

1. 说明

当从机被指派 “附属于” 主机时,两个节点之间需要进行初次数据同步。

2. 具体流程

  • 第一阶段:主从库建立连接、协商同步

    • 从库给主库发送 psync ? -1 命令,表示要进行数据同步

      1
      psync runID offset
      • runID:每个 Redis 实例启动时自动生成的唯一 ID,用于唯一标识实例
      • offset:写入位置

      由于从库并不知道主库的 runID,因此设为 ?;

      offset 设为 -1,表示第一次复制

    • 主库收到 psync 命令后,会用 FULLRESYNC 命令将主库 runID 和 offset 发送给从库

    • 从库接收 FULLRESYNC 命令,保存主节点信息

  • 第二阶段:主库发送所有数据,从库接收数据并加载

    • 主库执行 bgsave 命令,生成 RDB 文件,将其发送给从库
    • 从库接收文件,清空当前数据库,加载 RDB 文件
  • 第三阶段:主库发送新写命令给从库

    • 在主库生成 RDB 文件的过程中,可能有新的写操作被执行,主库会在内存中用专门的 replication buffer 记录此过程中的所有写操作,并将其发送给从库
    • 从库接收修改操作后执行,从而实现了主从库的同步

3. 性能消耗

在主从库的初次同步中,对于主库而言,有这两个影响性能的操作:

  • 生成 RDB 文件:fork() 操作会堵塞主线程,影响正常请求的处理
  • 传输 RDB 文件:文件的传输会占用网络带宽

如果从库很多,并且都要和主库进行初次同步,这将给主库带来非常大的性能压力。

可以通过 “主 - 从 - 从” 模式解决这一问题,即从库不再都和主库连接,而是和其它从库连接。

二、持续同步

一旦主从库完成了初次同步,他们之间便会一直维护一个网络连接,主库会将后续的写命令同步给从库,这个过程也被称为 “基于长连接的命令传播”,

三、常见问题

1. 为什么初次同步不使用 AOF?

  • RDB 文件是经过压缩的二进制数据,相对更小;

    而 AOF 文件是对写操作命令的记录,相对更大

  • 在从库加载文件时,RDB 文件可以直接解析还原,速度更快;

    AOF 文件需要依次重放每个命令,这个过程需要冗长的处理

2. 网络断连会怎么样?

如果网络断连,主从库之间的长连接将会断开,从库的数据自然也就没有办法和从库保持一致,这时候应该如何解决?

  • 在 Redis 2.8 之前,主从库需要重新同步,开销非常大

  • 在 Redis 2.8 之后,支持增量同步,主库可以在连接重新建立后将断连期间的命令发给从库同步,避免了重新同步

    主库会维护一个 repl_backlog_buffer 环形缓冲区,将所有的命令存储于以循环队列中。主库会记录自己的写入位置,从库会记录自己的读入位置。

    具体做法是:

    • 当主从库连接恢复之后,从库会首先给主库发送 psync 命令,说明自己的写入位置(offset)
    • 主库接收到 psync 命令后,会判断读入位置是否存在于循环队列,
      • 如果不存在(读入位置已经被循环队列覆盖),则执行初次同步
      • 如果存在,则执行持续同步

3. 为什么主机应该开启持久化?

假如主机未开启持久化且开启了自动重启,当主机崩溃以后,它将自动重启且因为没有初始化而数据清空,此时主从同步将导致从机上的数据也被清空。

参考