Redis高可用之主从复制原理演进分析( 二 )


增加了部分重同步,这个要怎么做才能兼容之前的全量同步呢?怎么知道从库复制到哪儿了?第一个从库肯定要记录下从库复制到哪儿了,下次断线重连时就可以告诉主库该从哪个地方开始复制了 。主库也要记录自己的一些复制信息 。Redis 用了几个概念就把这些问题给解决了 , Replication ID,offset,replication_backlog 。

  • Replication ID:复制 ID 。这是一个较大的随机字符串,标记一个给定的数据集 。每个主节点都会用这个 Repli ID 来标识内部数据集,从节点 ID 。当从节点加入时 , 这个 repli id 就初始化了 。
  • offset:复制偏移量 。每个主节点都有这个 offset 偏移量 , 主节点将自己产生的数据发送给从节点时,发送多少字节数据,自身 offset 就会增加多少 。从节点也有自己 offset,从节点写入数据时,offset 也会增加 。断线重连时,就可以知道从哪里开始同步了 。offset 需配合下面的复制积压缓冲区工作 。
  • replication_backlog:复制积压缓冲区 。它是在主节点上的一个环形缓冲区,用来存储主节点向从节点传递的命令 。它是大小固定 , 存储的命令有限,所有超出了就会删除 。从节点进行增量同步时,主节点会根据 offset 从 replication_backlog 中拷贝从节点缺失的数据到从节点 。
Replication ID, offset,这一对来标识数据集版本 。
Redis2.8之后就是用上面这几个概念实现部分数据重同步的 。从节点发送主节点的 replid 和从节点的一个 offset,主节点拿到这个replid 和自己的 replid 比较,如果是一样,并且这个 offset 也在 backlog 中能找到,那就可以可以进行部分重同步 。
全量复制步骤
  1. 主从节点先建立连接
建立连接后,从节点使用命令 PSYNC <replid> <offset> 向主节点发起同步请求 。如果主从节点是第一次复制,那么命令为 PSYNC ? -1 , replid 为 ?,因为是第一次复制不知道主库的 replid 。offset 为 -1,表示第一次复制 。
主节点收到 PSYNC 命令后,会用 FULLRESYNC 命令响应,带上主节点的 replid 和 offset 返回给从库,从库会记录下这两个参数 。便于以后判断是否需要部分重同步 。
  1. 同步数据
主节点执行 bgsave 命令生成 RDB 文件,生成完后把文件发送给从节点 , 从节点加载 RDB 文件 。这个过程中,主节点不会阻塞,依然会接收客户端的命令请求,当然,这些请求不会写在之前的 RDB 文件里,为了保持主从数据一致,这些命令会存储在 replication buffer 中 , 记录 RDB 文件后的所有写操作 。
  1. 同步缓冲的命令数据
协商就是根据先前定义好步骤来发送相关命令,为同步做准备工作 。有点协议的意思 。步骤如下:
当主库把 RDB 文件传送给从节点完成后,就会把 replication buffer 中的写命令操作发送给从节点,从节点执行这些操作命令,主从节点同步完成 。
  1. 命令传播
之后会继续向从节点发送主节点的操作命令,从节点执行这些命令,保持主从数据的一致 。
上面是一个主体的同步步骤,更加详细的步骤要分析源码了 。
发送步骤与 Redis2.8 之前全量同步没有多大区别 。
部分数据同步部分数据同步,解决的是主从节点在同步命令时候,网络断了在连上时,Redis2.8 之前会在全量同步数据 , 显然开销太大,不合理 。能不能只把断线后的数据同步一份,而不是全量同步?
网络断线后,就有部分命令数据没有同步到从节点上去,那我们能不能保存这部分命令数据?重连后 , 将断开期间的这部分命令重新同步给从节点,这样就不需要全量同步 。
Redis2.8 之后引入了 replication_backlog 复制积压缓冲区,前面有讲到这个概念 。命令一方面会传输给从节点,另外还会记录在这个复制积压缓冲区里 。Redis 使用一个环形缓冲区的结构保存最近的一些命令 。在缓冲区中,对字节进行编号 , 这个编号在 Redis 中叫复制偏移量 。
Redis高可用之主从复制原理演进分析

文章插图
是否部分同步条件?
  • 从节点 replid 和 主节点的 replid 相同
  • 复制偏移量 offset 在复制积压缓冲区的 backlog_off 和 offset 范围之间 。
如果满足上面的 2 个条件,就进行部分数据重同步 。

推荐阅读