旧版复制功能在处理断线复制情况时,会重复复制之前已经复制过的部分数据,造成效率低下问题。Redis从2.8版本开始,使用PSYNC命令
替代了旧版的SYNC命令来执行复制操作
。
PSYNC命令具有完整重同步(full synchronization)和部分重同步两种模式(partial synchronization)
:
- 完整重同步:处理初次复制情况,从服务器(Slave)先让主服务器(Master)创建并发送RDB文件,然后再将主服务器的缓冲区里的命令发送给从服务器,以此完成同步;
- 部分重同步:用于处理断线后复制的情况,在断线重连后,
只要将断线期间主服务器产生的命令发送给从服务器
,就可以完成数据同步了。
一、复制操作的实现
客户端向从服务器Slave发送SLAVEOF命令
,可以让这台从服务器去复制主服务器:
SLAVEOF <master_ip> <master_port>
第1步:设置主服务器的地址和端口
从服务器接收到SLAVEOF命令的master_ip和master_port参数之后,会保存到本地。并向客户端返回OK,表示已经收到复制命令,可以开始复制了。
第2步:建立套接字连接
从服务器发送完OK之后,就开始IP地址和端口创建连向主服务器的套接字连接。如果连接成功,从服务器会从套接字中接收到accept文件事件,从服务器的文件事件处理器会为这个套接字关联一个复制功能事件处理器
。这个复制功能事件处理器会负责后续的接收RDB以及其他命令的写入
。此时,从服务对于主服务器来说就是一个客户端。
第3步:发送PING命令
主从建立完连接之后,从服务器第一件事就是向主服务器发送一条PING命令,用来判断连接是否正常以及用来检查主服务器能否正常处理命令请求
。如果主服务器返回PONG,表示一切正常。否则从服务器断开连接并重连主服务器。
第4步:身份验证
- 如果从服务器设置了masterauth选项,则需要进行身份验证;
- 如果从服务器没有设置masterauth选项,则不需要进行身份验证。
身份验证主要是通过AUTH命令来执行的,验证流程如下:
第5步:发送端口信息
从服务器向主服务器发送自己的监听端口号,主服务器保存之后,用于后续的向从服务器写入命令的操作。
第6步:同步
从服务器向主服务器发送PSYNC命令
,执行同步操作,将自己的数据更新至主服务器当前的状态。同步操作执行之前,从服务器是主服务器的客户端,只有从服务器向主服务器发送命令并得到响应。但是同步操作开始之后,主服务器也需要向从服务器写入命令,这也是同步操作的基础,所以此时主从互为对方的客户端
。
第7步:命令传播
当完成同步之后,主从服务器就会进入命令传播阶段
,这时候主服务器只要一直将自己执行的写命令发送给从服务器
,而从服务器只要一直接受主服务器发送过来的写命令,两者保持一致即可。
同时命令传播阶段,从服务器还会每秒一次发送心跳包给主服务器
。
二、部分重同步的实现
部分重同步是为了处理断线之后重新复制的情况。部分重同步主要由以下三个部分构成:
- 主服务器的复制偏移量(replication offset)和从服务器的复制偏移量;
- 主服务器的复制积压缓冲区(replication backlog);
- 服务器的运行ID(run ID)
1. 复制偏移量
主从服务器分别会维护一个复制偏移量:
- 主服务器每次向从服务器
传播N个字节的数据后
,就会将自己的偏移量加N; - 从服务器每次收到主服务器发送过来的N个字节后,就会将自己的偏移量加N。
通过对比主从服务器的复制偏移量,可以知道主从是否一致:
- 如果主从复制偏移量一致:说明主从服务器状态一致;
- 如果主从复制偏移量不同:说明主从服务器不一致。不一致就需要进行部分重同步或者完整重同步了。
2. 复制积压缓冲区
复制积压缓冲区是主服务器维护的一个固定长度(fixed-size)的先进先出(FIFO)队列
,默认大小为1MB。
当主服务器传播命令时,它不仅会将命令发送给从服务器,还会写入复制积压缓冲区。因此,复制积压缓冲区里保存了最近一部分传播的命令
。并且复制复制积压缓冲区还保存了每个字节内容对应的偏移量
。如下图:
当从服务器断线重连之后,从服务器会通过PSYNC带上自己的复制偏移量offset,主服务器收到之后会和自己的复制偏移量比较,并执行不同的操作:
- 如果
offset偏移量之后(offset+1开始)的数据仍然在复制积压缓冲区中
,那么主服务器会对从服务器进行部分重同步操作
; - 如果
offset偏移量之后的数据不在复制积压缓冲区中
,那么会进行完整重同步操作
。
服务器的运行ID
run ID 就是用来标识各个服务器的唯一性的,这样在同步的时候就不会发生错乱了。
THE END.