redis主从数据同步原理

what:

  redis高可用

    1、数据尽量不丢失;

    2、尽可能的提供服务;

    栗子:AOF 和 RDB 保证了数据持久化尽量不丢失

      主从复制就是增加副本,一份数据保存到多个实例上。即使有一个实例宕机,其他实例依然可以持续服务

 

  主从

    复制——为单向的,即:只能从主复制到从;

    读写指责——读:主从都可以读。 写:主库先执行,之后将些操作同步到从库。一般master提供写,slave提供读。

 

  client buffer

    Redis 和客户端通信也好,和从库通信也好,Redis 都分配一个内存 buffer 进行数据交互,客户端就是一个 client,从库也是一个 client,我们每个 client 连上 Redis 后,Redis 都会分配一个专有 client buffer,所有数据交互都是通过这个 buffer 进行的。

 

  RDB和AOF文件对比:

    a、RDB 文件是二进制文件,网络传输 RDB 和写入磁盘的 IO 效率都要比 AOF
    b、从库进行数据恢复的时候,RDB 的恢复效率也要于 AOF。

  

how:

  第一次全量复制

    分3个阶段:连接建立阶段(即准备阶段)-> 主库同步数据到从库阶段 -> 发送同步期间新写命令到从库阶段

 

     连接建立阶段:从库执行 replicaof(之前是slave of) 并发送 psync 命令,表示要执行数据同步,主库收到命令后根据参数启动复制。命令参数包含了:主库的 runID 和 复制进度 offset 。主库FULLRESYNC 响应表示第一次复制采用的全量复制,也就是说,主库会把当前所有的数据都复制给从库。

      runID:每个Redis 实例启动都会自动生成一个 唯一标识 ID(runID),第一次主从复制,还不知道主库 runID,参数设置为空;
      offset:记录复制进度偏移量,第一次复制为-1;

 

    数据同步:master 执行 bgsave命令生成 RDB 文件,并将文件发送给从库,同时主库为每一个 slave 开辟一块 replication buffer 缓冲区记录从生成 RDB 文件开始收到的所有写命令; slave收到 RDB 文件后保存磁盘,并清空当前数据库的数据,再加载 RDB 文件数据到内存中;

 

    发送同步期间新写命令到从库:从节点加载 RDB 完成后,主节点将 replication buffer 缓冲区的数据发送到从节点,Slave 接收并执行,从节点同步至主节点相同的状态;

      replication buffer 缓冲区的数据:
        1)master 执行 bgsave 产生 RDB 的期间的写操作;
        2)master 发送 rdb 到 slave 网络传输期间的写操作;
        3)slave load rdb 文件把数据恢复到内存的期间的写操作;

      replication buffer注意:太小会导致主从复制连接断开,由 client-output-buffer-limit slave 设置。

 

  增量复制

    用于网络中断等情况后的复制,只将中断期间主节点执行的写命令发送给从节点,与全量复制相比更加高效(redis 2.8之后增加)。

    原理:repl_backlog_buffer。不管在什么时候 master 都会将写指令操作记录在 repl_backlog_buffer 中。因为内存有限, repl_backlog_buffer 是一个定长的环形数组,如果数组内容满了,就会从头开始覆盖前面的内容。master 使用 master_repl_offset记录自己写到的位置偏移量,slave 则使用 slave_repl_offset记录已经读取到的偏移量。

 

     

    增量复制如下:master 只需要把 master_repl_offset与 slave_repl_offset之间的命令同步给从库即可。

计算公式:repl_backlog_buffer = 2 * second * write_size_per_second;(second:从服务器断开重连主服务器所需的平均时间;
write_size_per_second:master 平均每秒产生的命令数据量大小(写命令和数据大小总和))

      注意:一旦被覆盖就会执行全量复制

   

 

  常态化同步

    这个过程也称为基于长连接的命令传播。使用长连接的目的就是:避免频繁建立连接导致的开销。

    还维持着心跳机制:PING 和 REPLCONF ACK。

 

  主从心跳机制

    主->从:PING
      每隔指定的时间,主节点会向从节点发送 PING 命令,这个 PING 命令的作用,主要是为了让从节点进行超时判断。

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

      REPLCONF ACK <replication_offset>
      其中 replication_offset 是从服务器当前的复制偏移量。发送 REPLCONF ACK 命令对于主从服务器有三个作用:

      a、检测主从服务器的网络连接状态
      b、辅助实现 min-slaves 选项。
      c、检测命令丢失, 从节点发送了自身的 slave_replication_offset,主节点会用自己的 master_replication_offset 对比,如果从节点数据缺失,主节点会从 repl_backlog_buffer缓冲区中找到并推送缺失的数据。注意,offset 和 repl_backlog_buffer 缓冲区,不仅可以用于部分复制,也可以用于处理命令丢失等情形;区别在于前者是在断线重连后进行的,而后者是在主从节点没有断线的情况下进行的。

 

  全量同步与部分同步

   具体过程如下:

 

     

    a、从节点根据当前状态,发送 psync命令给 master:
      I、如果从节点从未执行过 replicaof ,则从节点发送 psync ? -1,向主节点发送全量复制请求;
      I、如果从节点之前执行过 replicaof 则发送 psync <runID> <offset>, runID 是上次复制保存的主节点 runIDoffset 是上次复制截至时从节点保存的复制偏移量。
    b、主节点根据接受到的psync命令和当前服务器状态,决定执行全量复制还是部分复制:
      I、runID 与从节点发送的 runID 相同从节点发送的 slave_repl_offset之后的数据在 repl_backlog_buffer缓冲区中都存在,则回复 CONTINUE,表示将进行部分复制,从节点等待主节点发送其缺少的数据即可;
      I、runID 与从节点发送的 runID 不同或者从节点发送的 slave_repl_offset 之后的数据已不在主节点的 repl_backlog_buffer缓冲区中 (在队列中被挤出了),则回复从节点 FULLRESYNC <runid> <offset>,表示要进行全量复制,其中 runID 表示主节点当前的 runID,offset 表示主节点当前的 offset,从节点保存这两个值,以备使用。

 

  replication buffer 和 repl_backlog

    

    replication buffer 对应于每个 slave,通过 config set client-output-buffer-limit slave设置。是主从库在进行全量复制时,主库上用于和从库连接的客户端的 buffer。
    repl_backlog_buffer是一个环形缓冲区,整个 master 进程中只会存在一个,所有的 slave 公用。repl_backlog 的大小通过 repl-backlog-size 参数设置,默认大小是 1M,其大小可以根据每秒产生的命令、(master 执行 rdb bgsave) +( master 发送 rdb 到 slave) + (slave load rdb 文件)时间之和来估算积压缓冲区的大小,repl-backlog-size 值不小于这两者的乘积。

 

  数据过期数据:

    节点不会主动删除数据。我们知道 Redis 有两种删除策略:
      惰性删除:当客户端查询对应的数据时,Redis 判断该数据是否过期,过期则删除。
      定期删除:Redis 通过定时任务删除过期数据。

    Redis 3.2 开始,通过从节点读取数据时,先断数据是否已过期。如果过期则不返回客户端,并且除数据。

 

  单机使用建议
    主节点单机内存除了绝对量不能太大,其占用主机内存的比例也不应过大:最好只使用 50% - 65% 的内存,留下 30%-45% 的内存用于执行 bgsave 命令和创建复制缓冲区。

    内存不能太大的原因:

      如果 Redis 单机内存达到 10GB,一个从节点的同步时间在几分钟的级别;如果从节点较多,恢复的速度会更。如果系统的读负载很高,而这段时间从节点无法提供服务,会对系统造成很大的压力。

      如果数据量过大,全量复制阶段主节点 fork + 保存 RDB 文件耗时过大,从节点长时间接收不到数据触发超时,主从节点的数据同步同样可能陷入“全量复制->超时导致复制中断->重连->全量复制->超时导致复制中断”……的循环。

      

 

posted @ 2022-08-28 11:18  修心而结网  阅读(1046)  评论(0编辑  收藏  举报