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


    本篇重点

    主从库同步原理、如何应对主从库间网络断连风险

    主从库同步:全量复制、基于长连接的命令传播、增量复制——应对主从库间的网络断连

    背景

    若Redis只有一个实例运行,当该实例服务宕机后,宕机这段时间内Redis无法为新来的数据请求提供服务。

    Redis采取的解决方案是——增加副本冗余量,即将一份数据同时保存在多个实例上——Redis主从库模式

    多实例保存同一份数据,需要考虑的问题:

    • 副本间的数据如何保持一致?——数据同步
    • 数据读写操作可以发给所有实例吗?——数据读写

    前言

    Redis高可靠性的保证

    • 数据尽量少丢失——持久化存储(AOF/RDB)
    • 服务尽量少中断——主从库(本质是增加副本冗余量)

    Redis主从库模式

    • Redis主从库模式:保证数据副本一致性,且主从库 “读写分离”
    • 读写分离:
      • 读操作:主从库都可接收
      • 写操作:主库接收并执行,然后由主库将写操作同步给从库
      • 主从库读写分离
        主从库读写分离
    • 主从库同步的三个问题:
      • 实现原理——如何完成主从库
      • 主库数据是一次性传给从库,还是分批同步?
      • 主从库间网络断连了,数据还能保持一致吗?

    1. 主从库第一次同步

    • replicaof命令——建立主从库关系[1]
      • 某Redis实例执行:replicaof 主库IP 主库port
      • 该实例与主库建立主从库关系,成为主库的从库
    • 主从库第一次同步的三个阶段(某实例第一次执行replicaof与主库建立连接)
      • 建立连接,协商同步
        • 从库->主库:psync
        • 主库->从库:FULLRESYNC
      • 数据同步
        • 主库->从库:RDB快照
        • 从库:清楚旧有数据,加载RDB
        • 主库在数据同步中,执行完RDB后,正常接收 & 执行的写操作会被写入 replication buffer 中
      • 同步数据同步期间到来的写操作——replication buffer
        • 主库->从库:replication buffer
        • 从库:重新执行replication buffer中的操作
    • Redis第一次主从同步流程
      Redis第一次主从同步流程
    • 命令及参数解释:
      • psync命令形式:psync runID offset
      • runID:Redis实例ID,首次连接主库ID未知,传?
      • offset:复制进度,第一次复制传-1
      • FULLRESYNC: 全量复制,第一次建立连接采用全量复制

    Q:主从库同步中,主库执行RDB快照时,需要fork bgsave子进程,若从库数量很多,则主库fork的压力就会增加,如何应对这种问题?缓解主库压力?

    A:主从级联模式——“主—从—从”,在从库间建立“主从”关系,分担主库全量RDB的压力

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

    • “主—从—从”模式:选择一个从库(内存配置较高),级联其他从库(replicaof)

    3. 基于长连接的命令传播——避免频繁建立连接

    • 主从库建立网络连接后,此时主从库间已经完成了一次全量复制,后续Redis实例会维护这个网络连接,在这个网络连接上进行 “写操作同步”
    • “主—从—从”模式
      “主—从—从”模式

    4. 增量复制——主从网络断连后的解决方案

    增量复制——仅同步断连期间主库收到的命令

    repl_backlog_buffer——环形缓冲区,存储主库收到的写命令——记录主/从的写/读进度,通过offset

    • master_repl_offset:主库写offset,递增值
    • slave_repl_offset: 从库读offset,递增值
    • 主从库连接期间,master_repl_offset == slave_repl_offset
    • 主从库断连后,master_repl_offset >= slave_repl_offset

    Redis增量复制流程

    • 断连期间
      • 主库->replication buffer: 存储写命令(用于写操作同步)
      • 主库->repl_backlog_buffer: 存储写命令
      • 主库:记录 master_repl_offset
    • 连接恢复时
      • 从库->主库: psync 主库runID slave_repl_offset
      • 主库->从库:slave_repl_offset之后的写命令(全量/增量)
      • 从库:执行这些写命令
    • Redis增量复制流程
      Redis增量复制流程

    Q: 主库写入速度快,从库读取慢,导致未读的命令被新写的命令覆盖,引起的主从库数据不一致问题如何预防?

    A:

    • 调整 repl_backlog_size 大小,通常 = 缓冲空间大小*2
    • 或采用切片集群分担单个主库的请求压力(将写请求分散到集群中)

    Q: 主从断连时间过长,导致slave_repl_offset上的未读数据已经被新写入操作覆盖(同上一个问题),如何数据同步?

    A: 主库采用全量复制

    • 主库判断被覆盖—— master_repl_offset - slave_repl_offset > repl_backlog_size (个人猜想)
    • 若上式成立,则执行全量复制,否则增量复制

    Q: 本篇讨论的都是“主库如何同步数据给从库”、“断连恢复后主库如何同步断连期间的数据给从库”的问题,那么当主库挂了,Redis如何对外提供服务?此时从库能起到什么样的作用?——主从库模式的重要功能——服务尽量少中断

    A: Redis的哨兵机制

    图片来源于极客时间专栏《Redis核心技术与实战》


    1. Redis5.0前使用slaveof命令 ↩︎

  • 相关阅读:
    IDEA热部署插件JRebel使用
    IntelliJ IDEA 代码注释
    解决redis显示中文为乱码问题
    C#的六种修饰符
    Bat批处理把文件夹包括子文件夹下面的某个文件复制到另一个目录下
    html不识别<br/>,后台返回<br/>,前端不换行解决办法
    C# Task的应用
    c# 生成json字符串和解析json字符串处理
    在 C# 中将 List<dynamic> 转换为 List<string>
    C#读取主从文件的excel并把结果为pass的文件打包
  • 原文地址:https://www.cnblogs.com/GuoYuying/p/15068518.html
Copyright © 2020-2023  润新知