部分重同步功能由以下三个部分构成:
(1)master和slave的复制偏移量
(2)master的复制积压缓冲区
(3)服务器的运行ID(run ID)
复制偏移量
master和slave会分别维护一个复制偏移量
master每次向slave传播N个字节的数据时,就将自己的复制偏移量的值加上N
slave每次收到N个字节的数据时,就将自己的复制偏移量的值加上N
例如,master和slave的复制偏移量的值都为10000,这时master向slave传播长度为99字节的数据,那么master的复制偏移量将更新为10000+99=10099,而slave在接收到数据之后,也会将复制偏移量更新为10099
假设一个场景
有一个master,3个slave(A B C),当前大家的偏移量都是10010,这时master开始传播33字节的数据,突然A断线了,B和C成功接收,master和B C的偏移量变为了10043,A的还是10010,这样就发生了数据不一致
当A重新连接后,会向master发送PSYNC命令,并告诉master自己的偏移量是10010,这时master应该对A进行完全重同步,还是部分重同步呢?如果是部分重同步,如何只发送断线期间这部分数据呢?这些问题就需要复制积压缓冲区来解决了
复制积压缓冲区
复制积压缓冲区是由master维护的一个固定长度得队列,默认大小为1MB
当master进行命令传播时,不仅会将写命令发送给所有slave,还会将写命令入队到复制积压缓冲区里面
复制积压缓冲区里会保存着一部分最近传播的写命令,和相应的复制偏移量
当slave重新连上master时,会通过PSYNC命令将自己的复制偏移量offset发送给master,master会根据offset来决定如何操作:
如果offset+1开始的数据仍然存在于复制积压缓冲区里面,那么执行部分重同步操作,否则,执行完全重同步
对应上面的场景
A向master发送PSYNC命令,并报告自己的偏移量是10010,master将检查偏移量10010之后的数据是否存在于复制积压缓冲区里面,结果发现这些数据仍然存在,就将复制积压缓冲区10010偏移量之后的所有数据都发送给A,A接收这些数据,完成状态同步
服务器运行ID
每个Redis服务器,都会有自己的运行ID,启动时自动生成,由40个随机的十六进制字符组成
当slave对master进行初次复制时,master会将自己的运行ID传送给slave,而slave则会将这个运行ID保存起来
当slave断线并重新连上一个master时,会发送之前保存的运行ID
如果运行ID相同,那么说明slave断线之前复制的就是当前连接的这个master,可以尝试执行部分重同步操作
如果运行ID不相同,那么说明slave断线之前复制的master并不是当前连接的这个master,master将执行完整重同步操作