06 | 数据同步:主从库如何实现数据一致?

158 阅读5分钟

1.基本概念

  • 高可用

    • 数据少丢失,如果Redis发生宕机,可以通过AOF(记录操作)和RDB(内存快照)恢复数据,保证少丢失数据
    • 服务少中断,通过增加冗余副本
  • Redis的主从库模式,数据副本一致,主从库间采用读写分离

    • 主库:负责读操作和写操作,将写操作同步到从库上
    • 从库:负责读操作
  • 如果使用读写分离,即使每一个redis实例只开一个进程,但是多个实例的单进程相当于还是多进程,会引入新的并发安全问题(需要引入分布式锁,增加其他开销)

  • 同步方式

    • 一次性复制
    • 分批同步

2.主从同步

2.1主从库间如何进行第一次同步?

  • replicaof(redis5.0以后)|slaveof(redis5.0之前)命令形成主库和从库关系,三个阶段完成数据第一次同步\

  • 从库命令:replicaof 172.16.19.3 6379

  • 同步三阶段

    • 1.主从库间建立连接、协商同步过程,为全量复制做准备

      • 作用:从库与主库建立连接后,告诉主库进行同步,主库确认回复后,主从库间就可以开始同步

      • 具体过程

        • 从库给主库发送 psync 命令,表示要进行数据同步,主库根据这个命令的参数来启动复制(主库的 runID,复制进度 offset)\

          • runID 每个 Redis 实例启动时都会自动生成的一个随机 ID,用来唯一标记这个实例(第一次设为?)\

          • offset 复制的偏移量 (第一次设为?)\

        • 主库执行FULLRESYNC 响应命令带上两个参数:主库 runID 和主库目前的复制进度 offset

          • FULLRESYNC 响应表示第一次复制采用的全量复制,也就是说,主库会把当前所有的数据都复制给从库
    • 2.主库将所有数据同步到从库(RDB)

      • 主库将所有数据同步给从库。从库收到数据后,在本地完成数据加载。这个过程依赖于内存快照生成的 RDB 文件

      • 主库执行 bgsave 命令,生成 RDB 文件,将文件发给从库\

      • 从库接收到 RDB 文件后,会先清空当前数据库,然后加载 RDB 文件\

        • 避免数据不一致
      • 注意:主库不会被阻塞,仍然可以正常接收请求

      • 为了保证主从库的数据一致性,主库会在内存中用专门的 replication buffer,记录 RDB 文件生成后收到的所有写操作\

    • 3.同步最新的操作到从库

      • 把此时 replication buffer 中的修改操作发给从库,从库再重新执行这些操作
      • 此时从库和主库就保持一致了

2.2主从级联模式分担全量复制时的主库压力

  • 全量复制中的耗时操作

    • 生成RDB文件(通过cow将内存数据写入磁盘)

      • 主库忙于 fork 子进程生成 RDB 文件,fork 这个操作会阻塞主线程处理正常请求,从而导致主库响应应用程序的请求速度变慢\
    • 传输RDB文件

      • 传输 RDB 文件也会占用主库的网络带宽,同样会给主库的资源使用带来压力(是g级别的文件)\
  • 使用主 - 从 - 从解决上述问题

    • 将主库的压力分散到从库上
  • 可以手动选择一个从库(比如选择内存资源配置较高的从库),用于级联其他的从库\

  • **第一次全量复制后,基于长连接的命令传播,可以避免频繁建立连接的开销
    **

**
**

2.3主从库间网络断了

  • 2.8之前,网络断开后进行一次全量复制,开销非常大

  • 2.8以后,网络断了之后,主从库会采用增量复制的方式继续同步(断开网络期间的操作复制一份)

  • 保持增量数据的关键 repl_backlog_buffer

  • 当主从库断连后,主库会把断连期间收到的写操作命令

    • 写入 replication buffer
    • 把这些操作命令也写入 repl_backlog_buffer 这个缓冲区
  • repl_backlog_buffer是一个环形缓冲区,主库会记录自己写到的位置,从库则会记录自己已经读到的位置(自己记录消费位置)(kafak是broker记录消费者消费的位置)\

  • master_repl_offset 主库偏移量

  • slave_repl_offset从库偏移量\

  • 恢复过程

    • 从库首先会给主库发送 psync 命令,并把自己当前的 slave_repl_offset 发给主库

    • 主库会判断自己的 master_repl_offset 和 slave_repl_offset 之间的差距\

    • 主库只用把 master_repl_offset 和 slave_repl_offset 之间的命令操作同步给从库就行\

  • 注意:因为 repl_backlog_buffer 是一个环形缓冲区,所以在缓冲区写满后,主库会继续写入,此时,就会覆盖掉之前写入的操作

  • 解决办法

    • 调整 repl_backlog_size 这个参数\

    • 缓冲空间的计算公式是:缓冲空间大小 (数据不一致的情况)= 主库写入命令速度 * 操作大小 - 主从库间网络传输命令速度 * 操作大小\

    • 实际情况可多扩充几倍

\

3.总结

  • 网络带宽也是计算机的一种资源

  • 长链接复制操作指令

  • 主从同步基本原理

    • 全量复制

      • 第一次不可避免
      • 使用主 - 从 - 从模式,来缓解主库的压力
    • 基于长链接的命令传播\

      • 常规同步阶段
    • 增量复制

      • 网络断连后使用
      • repl_backlog_size设置较大,否则会导致数据被覆盖\
  • 两个buffer(缓冲区)

    • repl_backlog_buffer(记录所有操作缓冲区)\

    • **replication buffer(记录需要发给从库|客户端的缓冲区)
      **

    • **my.oschina.net/u/3847203/b…
      **

  • 两个offset

    • master_repl_offset\

    • **slave_repl_offset
      **

\