【Redis】主从复制

主从复制

为了避免单点故障,多个服务器保存同一份数据,这样即使有一台服务器出现了故障,其他服务器依然可以继续提供服务。

Redis 提供了主从复制模式来实现,该模式保证了多台服务器的数据一致性,主从服务器之间采用的是 读写分离的方式。

也就是说,所有的数据修改只在主服务器上进行,然后将最新的数据同步给从服务器,这样就使得主从服务器的数据是一致的。


第一次同步

我们可以使用replicaof(Redis 5.0之前使用slaveof)命令形成主服务器和从服务器的关系。

主从服务器的第一次同步的过程可分为三个阶段,如图:

微信图片_20211203225001

  1. 执行replicaof命令后,从服务器就会给主服务器发送psync命令,表示进行同步。psync命令包含两个参数,分别是主服务器的runlD和复制进度offset

    • runID,每个 Redis 服务器在启动时都会自动生产一个随机的 ID 来唯一标识自己。当从服务器和主服务器第一次同步时,因为不知道主服务器的 run ID,所以将其设置为 "?"。

    • offset,表示复制的进度,第一次同步时,其值为 -1。

  2. 主服务器用 FULLRESYNC 作为响应命令返回给对方,并且会带上两个参数,主服务器的 runID 和主服务器目前的复制进度 offset。

    FULLRESYNC 响应命令的意图是采用 全量复制 的方式,就是主服务器会把所有的数据都同步给从服务器。

  3. 接着,主服务器会执行bgsave命令来生成RDB文件,然后把文件发送给从服务器。从服务器收到RDB文件后,会先清空当前的数据,然后载入RDB文件。

    在生成RDB的这个过程不会阻塞主线程,在这期间的写操作命令会写到replication buffer缓冲区里。

  4. 在生成的RDB文件发送后,将replication buffer缓冲区里记录的写操作命令发送给从服务器,然后执行这些操作


基于长连接的命令传播

主从服务器在完成第一次同步后,双方会维护一个TCP 链接来保证主从服务器的数据一致性

后续主服务器可以通过这个连接将写操作命令传播给从服务器,然后从服务器执行该命令,使得与主服务器的数据库状态相同。

而且这个连接是长连接,目的是避免频繁的TCP连接和断开带来的性能开销。


增量复制

从服务器对主服务器的复制可以分为两种情况:

  • 初次复制:从服务器以前没有复制过任何主服务器,或者从服务器当前要复制的主服务器和上一次复制的主服务器不同。

  • 断线后重复制:在Redis 2.8 之前,处于命令传播阶段的主从服务器因为网络原因而中断了命令同步,但又重连上了,从服务器会和主服务器重新进行一次全量复制,但是这样效率非常低。

所以在Redis 2.8 开始,全量复制用于初次复制的情况。网络断开又恢复后,主从服务器会采用 增量复制 的方式继续同步,也就是只会把网络断开期间主服务器接收到的写操作命令,同步给从服务器。

主要步骤:

  1. 从服务器恢复网络后,发送psync命令,此时offset参数不是-1;
  2. 主服务器收掉命令后,用CONTINUE响应命令告诉从服务器接下来采用增量复制的方式同步数据;
  3. 然后主服务将主从服务器断线期间,所执行的写命令发送给从服务器,然后从服务器执行这些命令。

那么主服务器怎么知道要将哪些增量数据发送给从服务器呢?

原因是有这两个东西:复制偏移量(replication offset) 和 复制积压缓冲区(repl_backlog_buffer) .

  • 复制偏移量:执行复制的主服务器和从服务器分别会维护一个复制偏移量,用来标记各自写或读取到的位置。如果两者偏移量不同,说明主从服务器并未处于一致状态。

  • 复制积压缓冲区:由主服务器维护的一个环形缓冲区,默认大小为1M,。在进行命令传播时,不仅会把写命令发送给从服务器,还会将写命令写到积压缓冲区中。当缓冲区写满后,主服务器继续写入的话,就会覆盖之前的数据。

在从服务器重新连上主服务器时,从服务器会通过psync命令将自己的复制偏移量offset发送给主服务器:

  • 如果offset偏移后的数据仍然存在于复制积压缓冲区中,那么就执行增量复制的同步操作。

  • 相反执行全量复制。

所以如果复制积压缓冲区配置的过小,主从服务器网络恢复时,可能发生「从服务器」想读的数据已经被覆盖了,那么这时就会导致主服务器采用全量复制的方式。所以为了避免这种情况的频繁发生,要调大这个参数的值,以降低主从服务器断开后全量同步的概率。


心跳检测

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

REPLCONF ACK <replication_offset>

replication_offset是从服务器当前的复制偏移量。

主要有三个作用:

  1. 检测主从服务器的网络连接状态
  2. 辅助实现min-slaves选项
  3. 检测命令丢失

参考

《Redis设计与实现》

https://mp.weixin.qq.com/s/WmG2vMhEgc7XHjeCFgSZTQ

posted @ 2021-12-04 00:24  CJ-cooper  阅读(63)  评论(0编辑  收藏  举报