Redis-主从复制

25 阅读5分钟

为避免单机故障,需要将数据复制到其他服务器上,这样即使一台服务出现了问题,其他服务器也可以快速对外提供服务,Redis 提供了主从复制模式来保证多台服务器之间的数据一致性

image.png

主从服务器之间如何同步

第一次同步

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

  • 第一阶段是建立链接、协商同步
  • 第二阶段是主服务器同步数据给从服务器
  • 第三阶段是主服务器发送新写操作命令给从服务器

image.png

第一阶段: 建立链接、协商同步 执行了 replicaof 命令后,从服务器就会给主服务器发送 psync 命令,表示要进行数据同步 psync 命令包含两个参数,分别是主服务器的 runID 和复制进度 offset

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

主服务器收到 psync 命令后,会用 FULLRESYNC 作为响应命令返回给对方,并携带主服务器的 runID 和主服务器目前的复制进度 offset

第二阶段: 主服务器同步数据给从服务器 主服务器会执行 bgsave 命令来生成 RDB 文件,然后把文件发送给从服务器

从服务器收到 RDB 文件后,会先清空当前的数据,然后载入 RDB 文件

这期间主节点新增的写操作并没写记录到RDB文件中,为了保证主从服务器的数据一致性,主服务器在下面这三个时间间隙中将收到的写操作命令,写入到 replication buffer 缓冲区里

  • 主服务器生成 RDB 文件期间;
  • 主服务器发送 RDB 文件给从服务器期间;
  • 「从服务器」加载 RDB 文件期间

第三阶段: 主服务器发送新写操作命令给从服务器 从服务器收到 RDB 文件后,丢弃所有旧数据,将 RDB 数据载入到内存。完成 RDB 的载入后,会回复一个确认消息给主服务器

主服务器将 replication buffer 缓冲区里所记录的写操作命令发送给从服务器,从服务器执行来自主服务器 replication buffer 缓冲区里发来的命令,这时主从服务器的数据就一致了

replication buffer 默认大小为1M

命令传播

主从服务器在完成第一次同步后,双方之间就会维护一个 TCP 连接,后续主服务器可以通过这个连接继续将写操作命令传播给从服务器,然后从服务器执行该命令,使得与主服务器的数据库状态相同

分摊主服务器压力

主从服务器在第一次数据同步的过程中,主服务器会做两件耗时的操作:生成 RDB 文件和传输 RDB 文件

主服务器是可以有多个从服务器的,如果从服务器数量非常多,而且都与主服务器进行全量同步的话,就会带来两个问题:

  • 由于是通过 bgsave 命令来生成 RDB 文件的,那么主服务器就会忙于使用 fork() 创建子进程,如果主服务器的内存数据非大,在执行 fork() 函数时是会阻塞主线程的,从而使得 Redis 无法正常处理请求;
  • 传输 RDB 文件会占用主服务器的网络带宽,会对主服务器响应命令请求产生影响

解决方案也很简单,使用 主-从-从的方式,让从节点也挂在从节点,在接受主节点数据的同时也将数据同步给自己的从节点

增量复制

如果主从服务器间的网络连接断开了,那么就无法进行命令传播了,这时从服务器的数据就没办法和主服务器保持一致了,这个时候就需要增量复制

image.png

主要有三个步骤:

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

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

  • epl_backlog_buffer,是一个「环形」缓冲区,用于主从服务器断连后,从中找到差异的数据;
  • replication offset,标记上面那个缓冲区的同步进度,主从服务器都有各自的偏移量,主服务器使用 master_repl_offset 来记录自己「」到的位置,从服务器使用 slave_repl_offset 来记录自己「」到的位置

repl_backlog_buffer的写入时机:

在主服务器进行命令传播时,不仅会将写命令发送给从服务器,还会将写命令写入到 repl_backlog_buffer 缓冲区里,因此 这个缓冲区里会保存着最近传播的写命令, 网络断开后,当从服务器重新连上主服务器时,从服务器会通过 psync 命令将自己的复制偏移量 slave_repl_offset 发送给主服务器,主服务器根据自己的 master_repl_offset 和 slave_repl_offset 之间的差距,然后来决定对从服务器执行哪种同步操作

  • 如果判断出从服务器要读取的数据还在 repl_backlog_buffer 缓冲区里,那么主服务器将采用增量同步的方式;
  • 相反,如果判断出从服务器要读取的数据已经不存在 repl_backlog_buffer 缓冲区里,那么主服务器将采用全量同步的方式

image.png

repl_backlog_buffer 缓行缓冲区的默认大小是 1M

总结

主从复制共有三种模式:全量复制、基于长连接的命令传播、增量复制