Redis——第15章:复制

    科技2026-04-17  2

    复制

    完整重同步部分重同步

    部分重同步的实现

    复制偏移量复制积压缓冲区服务器运行ID

    PSYNC过程的实现

    建立连接和同步判断(完整/部分)复制数据

    复制(建立连接 + 身份验证 + PSYNC + 数据同步)

    建立连接后的心跳检测

    每秒发送命令三个作用(检测网络状态,min-slaves配置,检测命令丢失)

    1.复制

    在redis中,用户可以通过执行SLAVEOF命令或者配置让一个服务器去复制另一个服务器 eg. 向服务器127.0.0.1:12345发送 SLAVEOF 127.0.0.1 6379命令,12345会变成6379的从服务器从2.8开始,redis使用PSYNC命令来代替SYNC执行复制时的同步操作PSYNC具有两种模式: 完整重同步(full resync) 从服务器发送同步请求(PSYNC)主服务器执行BGSAVE,在后台生成RDB文件,并使用一个缓冲区记录从现在开始执行的所有写命令RDB完成后,主服务器发送给从服务器RDB文件主服务器发送缓冲区中的内容部分重同步(partial resync) 适用于断线重连情况

    2.部分重同步的实现

    (1)复制偏移量

    复制的双方——主服务器和从服务器分别维护一个复制偏移量

    eg.主从服务器现在的复制偏移量都是10086,如果主服务器向从服务器A,B,C传播33字节,而A断线了,则情况如下

    (2)复制积压缓冲区

    是由主服务器维护的一个固定长度,先进先出的队列,默认1MB。

    主服务器在复制时不仅会把命令发送给所有从服务器,也会写入复制挤压缓冲区。如下所示

    当从服务器断线重连时,会通过PSYNC命令将自己的offset发送给主服务器。

    主服务器判断offset后面缺失的内容是否在积压缓冲区中:

    如果在:则回复+CONTINUE,表示采用部分重同步来恢复。并将缺失的数据发送给从服务器如果不在:则进行完整重同步

    缓冲区大小默认1MB,可以根据conf中repl-backlog-size来修改大小

    (3)服务器运行ID

    每个服务器,无论主从,都有自己的运行ID:40个随机16进制字符,在服务器启动时自动生成

    当从服务器初次复制时,主服务器会发送自己的ID,从服务器会保存。当从服务器断线重连时,向主服务器发送之前记录的ID 如果相同,说明是断线重连前的那个主服务器,可以尝试进行partial resync如果不相同,说明主服务器已经换了,必须fully resync

    3. PSYNC过程的实现

    从服务器发送PSYNC命令,请求复制

    如果从服务器以前没有复制过任何主服务器,则向主服务器发送 PSYNC ? -1 的命令,表示请求完整重同步如果之前已经复制过某主服务器,则向主服务器发送 PSYNC <runid> <offset> ;runid是上次复制的主服务器ID;offset是从服务器当前的复制偏移量

    主服务器回复有三种情况:

    +FULLRESYNC <runid> <offset> : 执行 fully sync,offset是主服务器的复制偏移量+CONTINUE:执行 partial sync,从服务器等待主服务器发送缺失的数据-ERR:主服务器版本低于2.8,识别不了PSYNC命令,需要从服务器发送SYNC命令

    例子:

    (1)从服务器的客户端——>从服务器: slaveof 127.0.0.1 6379

    (2)从服务器——>主服务器:PSYNC ? -1

    (3)主服务器——>从服务器:FULLRESYNC 53b9b28df8042fdc5ab5e3fcbbbabff1d5dce2b3 10086

    (4)完整重同步成功,主从服务器保持一致,offset一直增加

    (4)offset同步到20000字节时,从服务器断开重连

    (5)从服务器——>主服务器:PSYNC 53b9b28df8042fdc5ab5e3fcbbbabff1d5dce2b3 20000

    (6)主服务器——>从服务器: + CONTINUE (发现缺失的数据仍在缓冲区中,可继续复制)

    4.复制的实现

    (1)从服务器设置地址和端口

    当从客户端发送salve指令时,从服务器会存储对于IP地址和端口号到redisServer中去。

    当设置属性完成后,从服务器返回给客户端OK指令。而实际的复制工作将在之后才执行

    struct redisServer{ //主服务器地址 char *masterhost; //主服务器端口 int masterport; }

    (2)从服务器建立socket连接

    从服务器根据IP和端口号,向主服务器建立连接。

    连接建立后,从服务器将为这个socket关联一个handler

    这时,从服务器可以被当作 主服务器的客户端。

    (3)从服务器发送发送PING命令

    从服务器成了主服务器的客户端之后,第一件事是发送PING命令,主服务器会有三种回复

    返回了一个回复超时——>网络状态不好,从服务器断开并重新连接返回一个ERROR——>主服务器可能在忙,从服务器断开并重新连接返回PONG——>成功,可以继续下一步

    (4)身份验证

    从服务器收到PONG之后,进行身份验证,主要根据conf中的配置。

    如果设置了masterauth,则从服务器会自动发送 AUTH password指令给主服务器进行验证

    eg.如果主服务器设置了密码为10086, 则从服务器会发送 AUTH 10086 //conf配置文件 slaveof <masterip> <masterport> //设置当本机为 slave 服务时,设置 master 服务的 IP 地址及端口,在 Redis 启动时,它会自动从 master 进行数据同步 masterauth <master-password> //作为slave时,需要给master提供的密码 requirepass foobared //本服务器自身的密码,客户端在连接 Redis 时需要通过 AUTH <password> 命令提供密码,默认关闭

    连接成功的情况:

    主服务器没有设置requirepass,从服务器也没有提供masterauth主服务器设置了requirepass,从服务器也提供了masterauth。两者相同

    其他情况都连接不成功

    (5)发送端口信息

    身份验证成功后,从服务器发送 REPLCONF listening-port <port-number>命令,向主服务器发送从服务器的监听端口号,主服务器记录在对应redisClient中

    typedef struct redisClient{ //从服务器的监听端口号 int salve_listening_port }

    该属性的唯一作用是:主服务器查看所有slave时:执行 INFO replication命令,打印所有从服务器的端口号

    (6)同步

    这一步中,主服务器和从服务器都是各自的客户端。执行PSYNC命令

    (7)命令传播

    完成同步之后,主服务器只要将自己执行的写命令同步给从服务器,就可以一直保持一致。

    5.心跳检测

    从服务器会以每秒一次的频率,向主服务器发送命令,其中replication_offset是从服务器当前的offset REPLCONF ACK <replication_offset>主要有三个作用 检测主服务器的网络状态 如果想看某一主服务器的所有从服务器延迟信息,可以发送 INFO replication指令 根据时间可以看到lag,正常的lag应该在0到1秒之间。如果超过了一秒,说明连接出了故障辅助实现min-slaves配置选项,有两个配置与此相关 min-slaves-to-write 3       如果从服务器的数量<3个,主服务器拒绝执行写命令min-slaves-max-lag 10        如果3个从服务器的lag都>=10秒时,主服务器拒绝执行写命令检测命令丢失 主服务器会根据发送过来的offset检测,是否与从服务器保持数据一致,如果不一致,则部分重传。
    Processed: 0.009, SQL: 9