:::tip
SLAVEOF host:port 命令可以将当前服务器去复制目标服务器,进行复制中的主从服务器的数据库将保存相同的数据,概念上称为数据库状态一致
:::
旧版复制功能
同步(sync)
当从服务器发送SLAVEOF
命令要求复制主服务器时,从服务器首先执行同步
操作,即将从服务器的数据库状态更新至主服务器当前所处的数据库状态,具体步骤如下
1、 从服务器发送SYNC
命令
2、 收到命令的主服务执行BGSAVE
命令,在后台生成RDB文件,并使用缓冲区记录从现在执行BGSAVE
之后执行的所有写命令
3、 主服务器执行完BGSAVE
之后,主服务器会将RDB文件发送给从服务器,从服务器接收并载入这个RDB文件
4、 主服务器将记录在缓冲区的所有写命令发送给从服务器,从服务器执行这些写命令
命令传播(command propagate)
同步操作完成后,主从服务器目前的数据库状态达到一致,但这种状态不是一成不变的,每当主服务器执行客户端发送的写命令时,主从服务器的数据库就不再一致
所以为了保持主从服务器的数据一致,主服务器需要对从服务器执行命令传播:将写命令发送给从服务器,当从服务也执行完后,主从服务器将再次回到一致状态
缺陷
旧版复制功能的缺陷主要体现在从服务器断线重连的处理
如上图的情况,从服务器在某一刻断线,再此期间主服务器增加了k3,k4两个键,按目前的实现逻辑,从服务器在之后重连后,依旧是再次发送SYNC
命令进行同步(主服务器生成和发送RDB文件给从服务器载入)
但其实从服务器主需要断线期间的k3,k4键即可,RDB文件中的其他键信息对从服务器来说都是不必要的
:::tip
SYNC是一个非常耗资源的操作
1、 主服务器需要执行BGSAVE来生成RDB文件,这耗费CPU,内存和磁盘IO资源
2、 主服务器需要将RDB发送给从服务器,这耗费网络带宽
3、 从服务器加载RDB文件时会阻塞其他命令的处理
:::
新版复制功能
PSYNC命令替代SYNC
为了解决断线重连后的重同步问题,Redis2.8以后使用了PSYNC
代替SYNC
进行同步操作,有以下两种模式:
1、 完整重同步:用于初次复制,执行步骤与SYNC基本一致。 PSYNC ? -1
2、 部分重同步:用于断线重连后的重复制,在条件允许的情况下,只需要将断开期间主服务器的写命令发送给从服务器 。PSYNC runid offset
以下是执行部分重同步时的通信过程
部分重同步的工作原理
部分重同步主要由三个部分组成
1、 主服务器的复制偏移量和从服务器的复制偏移量
2、 主服务器的复制积压缓冲区
3、 服务器的运行ID
复制偏移量
每一个服务器都会分别维护一个复制偏移量:
1、 主服务每次向从服务器传播N个字节的数据(写命令)时,就将自己的复制偏移量加N
2、 从服务每次收到主服务器传播的N个字节的数据(写命令)时,就将自己的复制偏移量加N
那么通过对比主从服务器的复制偏移量就可以知道
1、 它们目前的状态是否一致
2、 它们之间缺失了多少数据
复制积压缓冲区
通过复制偏移量可以知道主从服务器之间缺失了多少数据,那么缺失的数据是什么?要去哪里找回来呢?
这里就用上了复制积压缓冲区了
当主服务器进行命令传播
时,它不仅将写命令发送给所有从服务器,还会将写命令放进一个固定长度的先进先出的队列
里,这个队列就是复制积压缓冲区(默认大小是1MB)
当从服务器重连后,从服务器通过PSYNC
命令将自己的复制偏移量发送给主服务器
1、 如果从服务器复制偏移量
之后的数据还在复制积压缓冲区
中,那么进行部分重同步
的操作
2、 如果从服务器复制偏移量
之后的数据不在复制积压缓冲区
中,那么进行完整重同步
的操作
:::tip
如何调整复制积压缓冲区的大小
通过redis.conf中的repl-backlog-size进行调整
一般调整为 2 * 断线重连所需的平均秒数 * 主服务器每秒产生的写命令数量
:::
服务器运行ID
:::tip
每个Redis服务器都拥有自己的运行ID
运行ID由服务器启动时生成,由40个随机的十六进制字符组成
:::
初次复制时,从服务器会保存主服务器的运行ID
当从服务器断线重连时,从服务器将这个运行ID发送给主服务器:
1、 如果与主服务器的运行ID相同
,则说明断线前复制的就是当前连接的主服务器,主服务器可以根据条件尝试进行部分重同步
2、 如果与主服务器的运行ID不同
,则说明断线前复制的不是当前连接的主服务器,主服务器将对从服务器进行完整重同步
PSYNC执行时可能遇上的情况
从服务器执行SLAVEOF的完整过程
1、 设置主服务器的地址和端口
2、 与主服务器建立套接字连接
3、 发送PING命令
4、 身份验证
5、 向主服务器发送从服务器端口信息 REPLCONF listening-port
7、 命令传播
心跳检测
:::tip
在命令传播阶段,从服务器默认一秒一次的速率,向主服务器发送指令
REPLCONF ACK <replication_offset>
其中replication_offset时从服务器当前的复制偏移量
:::
发送REPLCONF ACK命令主要由三个作用:
1、 检测主从服务器的连接状态
2、 辅助实现min-slaves配置选项
3、 检测命令丢失
参考
1、 Redis设计与实现