美文网首页redis系列
redis系列(五):主从同步

redis系列(五):主从同步

作者: 范柏柏 | 来源:发表于2020-05-30 17:29 被阅读0次

    就是从库和主库的数据要保持一致,主库的数据同步到从库的过程。

    现有两个redis

    • 127.0.0.1:6379
    • 127.0.0.1:12345
    127.0.0.1:12345 > slaveof 127.0.0.1:6379
    

    这个时候,12345就是6379的从库了。

    复制分为全量复制和增量复制。
    全部复制触发在从库初始化的时候。
    其他情况都是走的增量复制。增量就是主库每次修改的数据。

    2.8之前的复制功能

    redis复制功能分为同步(sync)和命令传播(command propagate)

    • 同步操作用于将从服务器,更新至与主服务器一致
    • 命令传播则用于,在主服务器被修改,导致主从不一致的时候,让主从重新回到一致的动作。

    同步

    当从服务器知道自己是从服务器,并初始化的时候,开始执行同步。
    过程:

    1. 从服务器想主服务器发送SYNC命令
    2. 收到SYNC命令的主服务器,执行BGSAVE命令,在后台生成一个RDB文件,并使用一个缓冲区记录从现在开始执行的所有写命令。
    3. 当主服务的BGSAVE命令执行完毕时,主服务器会将刚生成的RDB文件发送给从服务器。从服务器接收并载入这个RDB文件,将自己的数据更新至与主服务器执行BGSAVE命令时的状态。
    4. 主服务器将记录在缓冲区里面的所有写命令发送给从服务器,从服务器执行这些命令,将自己的数据库状态更新至主服务器当前所处的状态。
    初始化同步过程.png
    时间 主服务器 从服务器
    T0 服务器启动 服务器启动
    T1 执行 set k1 v1
    T2 执行 set k2 v2
    T3 执行 set k3 v3
    T4 向主服务器发送SYNC命令
    T5 接收到从服务器的SYNC命令,执行BGSAVE命令,创建包含k1、k2、k3的RDB文件,并使用缓冲区记录接下来执行的所有写命令
    T6 执行 set k4 v4,并将这个命令记录到缓冲区
    T7 执行 set k5 v5,并将这个命令记录到缓冲区
    T8 BGSAVE命令执行完毕,向从服务器发送RDB文件
    T9 接收并载入主服务器发来的RDB文件,获得k1,k2,k3三个键
    T10 向从服务器发送缓冲分区保存的写命令set k4 v4和set k5 v5
    T11 接收并执行主服务器发来的两个set命令,得到k4,k5两个键
    T12 同步完成,现在主从服务器两者的数据库都包含了键k1,k2,k3,k4,k5 同步完成,现在主从服务器两者的数据库都包含了键k1,k2,k3,k4,k5

    命令传播

    当复制执行完了,以后主库的修改怎么做到的主从一致呢,这就要用到命令传播了。

    当主库删除了k3,让从库也得删除k3。就要把del k3这个命令发送给从服务器。从服务器收到后,执行,这样就又一致了。完事。

    老版本的缺陷

    • 初次同步。从服务器以前没有复制过任何主服务器,或者从服务器当前要复制的主服务器和上一次复制的主服务器不同。
    • 断线后再次同步。处于命令传播阶段的主从服务器因为网络原因而中断了复制,从服务器通过自动重连,重新连上了主服务器,这时候开始继续复制主服务器。

    初次复制。没有问题。问题出在了断线后再次复制。看下过程:

    时间 主服务器 从服务器
    T0 主从服务器完成同步 主从服务器完成同步
    T1 执行 set k1 v1 执行主服务器传来的 set k1 v1
    T2 执行 set k2 v2 执行主服务器传来的 set k2 v2
    ... ... ...
    T10085 执行并传播set k10086 v10086 执行主服务器传来的 set k10085 v10085
    T10086 执行并传播set k10086 v10086 执行主服务器传来的 set k10086 v10086
    T10087 主从服务断开连接 主从服务断开连接
    T10088 执行set k10087 v10087 断线中,尝试重新连接主服务器
    T10089 执行set k10088 v10088 断线中,尝试重新连接主服务器
    T10090 执行set k10089 v10089 断线中,尝试重新连接主服务器
    T10091 主从服务器重新连接 主从服务器重新连接
    T10092 向主服务器发送SYNC命令
    T10093 收到从服务器发来的SYNC命令,执行BGSAVE命令,创建包含k1值k10089的RDB文件,并使用缓冲区记录接下来执行的所有写命令
    T10094 BGSAVE执行完毕,向从服务器发送RDB文件
    T10095 接收并载入主服务器发来的RDB文件,获得k1至k10089
    T10096 因为BGSAVE命令执行期间,主服务器没有执行写命令,所以不会发送缓冲区的写命令
    T10097 主从服务器再次完成同步 主从服务器再次完成同步

    问题就在T10093。他把所有的数据都放RDB传给从服务器了。从服务器k1至k10086都是有的。不用在来一遍。所以新版本复制功能就出来的,主要原则是引入了offset。

    2.8之后的复制功能

    2.8之后的同步命令不是SYNC了,而是PSYNC。

    PSYNC分两种:

    • 完成重同步。和旧版本SYNC一样,也是全量RDB发送给从库。
    • 部分重同步。这就不一样了。只把断线重连这段时间的写命令发送给从服务器,从服务器接收到这些命令,主从就一致了。
    时间 主服务器 从服务器
    T0 主从服务器完成同步 主从服务器完成同步
    T1 执行 set k1 v1 执行主服务器传来的 set k1 v1
    T2 执行 set k2 v2 执行主服务器传来的 set k2 v2
    ... ... ...
    T10085 执行并传播set k10086 v10086 执行主服务器传来的 set k10085 v10085
    T10086 执行并传播set k10086 v10086 执行主服务器传来的 set k10086 v10086
    T10087 主从服务断开连接 主从服务断开连接
    T10088 执行set k10087 v10087 断线中,尝试重新连接主服务器
    T10089 执行set k10088 v10088 断线中,尝试重新连接主服务器
    T10090 执行set k10089 v10089 断线中,尝试重新连接主服务器
    T10091 主从服务器重新连接 主从服务器重新连接
    T10092 向主服务器发送PSYNC命令
    T10093 向从服务器返回+continue回复,表示执行部分重同步
    T10094 接收+continue回复,准备执行部分重同步
    T10095 向从服务器发送set k10087 v10087、set k10088 v10088、set k10089 v10089三个命令
    T10096 接收并执行主服务器传来的三个set命令
    T10097 主从服务器再次完成同步 主从服务器再次完成同步

    部分重同步由三个部分构成

    • 主服务和复制偏移量和从服务器的复制偏移量
    • 主服务器的复制积压缓冲区
    • 服务器运行的ID(run ID)

    复制偏移量

    一张图你就明白了


    初始化状态.png 正常情况.png A掉线了.png

    复制积压缓冲区

    复制积压缓冲区是一个由主服务器维护的一个固定长度,先进先出队列。默认大小1MB。

    在命令传播过程中,主库的过程:


    命令传播.png

    当从服务器连接上主服务器时,从服务器会通过PSYNC命令将自己的复制偏移量offset发送给主服务器,主服务器会根据这个复制偏移量来决定对服务器进行何种同步操作:

    • 如果offset偏移量之后的数据,仍然存在于复制积压缓冲区里面,那么主服务器将对从服务器执行部分重同步。

    • 相反,offset之后的数据,不在复制积压缓冲区中(两种情况,1.掉线时间太长。2.换了新的主),那么进行完整重同步。

    回到刚刚断线重连表格的那个例子:

    1. 当从服务器A重连后,向主服务器发送PSYNC命令,报告自己的复制偏移量为10086

    2. 主服务器收到从服务器的PSYNC命令以及10086偏移量之后,主服务器将检查偏移量之后的数据是否还存在与复制积压缓冲区中,结果发现仍然存在,于是想从服务器发送+continue回复,表示以部分同步模式来进行。

    3. 接着主服务器会将复制积压缓冲区10086偏移量之后的所有数据(10087至10119)都要发送发给给从服务器。

    4. 从服务器接收到这33字节的缺失数据,就可以回到与主服务器一致的状态。

    服务器运行ID

    不管主从,服务器启动时,都会生成一个ID。

    当主从初次复制的时候,从库会保存自己主库的ID。

    当从断线并重新连上一个主服务器,从服务器会把上次复制的主服务器ID,发送给当前的主库。主库收到之后会判断:

    • 和自己一样。说明之前就是我的从,可能就会执行部分重同步。(缓冲区没有了就完成重同步了)。

    • 和自己不一样。说明之前是别人的从,第一次成为我的从,必然会执行完整重同步。

    如果在传输过程中,数据丢了怎么办

    主库给从库发送10087至10119这段偏移量的所有数据,但网络问题丢了。在从库想主库每秒发送心跳的时候,心跳包中会包含从库的offset,如果不一样,把差掉的补发。(2.8之前没有这个功能)。

    知识点

    当从库接收主库的全量RDB文件。在载入RDB文件的时候,从库是不可用的

    相关文章

      网友评论

        本文标题:redis系列(五):主从同步

        本文链接:https://www.haomeiwen.com/subject/wkhhzhtx.html