前面也提到了,Redis2.8之前,断线后同步会重新执行SYNC命令,这是非常低效的。下面我们来看一下Redis2.8之后是怎么进行同步的。
Redis从2.8版本开始,使用PSYNC命令来替代SYNC命令执行复制时同步的操作。
PSYNC命令具有完整重同步和部分重同步两种模式(其实就跟上面所说的初次复制和断线后复制差不多个意思)。
2.1.2完整重同步
下面先来看看完整重同步是怎么实现的:
- 从服务器向主服务器发送PSYNC命令
- 收到PSYNC命令的主服务器执行BGSAVE命令,在后台生成一个RDB文件。并用一个缓冲区来记录从现在开始执行的所有写命令。
- 当主服务器的BGSAVE命令执行完后,将生成的RDB文件发送给从服务器,从服务器接收和载入RBD文件。将自己的数据库状态更新至与主服务器执行BGSAVE命令时的状态。
- 主服务器将所有缓冲区的写命令发送给从服务器,从服务器执行这些写命令,达到数据最终一致性。
完整重同步
2.1.2部分重同步
接下来我们来看看部分重同步,部分重同步可以让我们断线后重连只需要同步缺失的数据(而不是Redis2.8之前的同步全部数据),这是符合逻辑的!
部分重同步功能由以下部分组成:
- 主从服务器的复制偏移量
- 主服务器的复制积压缓冲区
- 服务器运行的ID(run ID)
首先我们来解释一下上面的名词:
复制偏移量:执行复制的双方都会分别维护一个复制偏移量
- 主服务器每次传播N个字节,就将自己的复制偏移量加上N
- 从服务器每次收到主服务器的N个字节,就将自己的复制偏移量加上N
通过对比主从复制的偏移量,就很容易知道主从服务器的数据是否处于一致性的状态!
复制偏移量
那断线重连以后,从服务器向主服务器发送PSYNC命令,报告现在的偏移量是36,那么主服务器该对从服务器执行完整重同步还是部分重同步呢??这就交由复制积压缓冲区来决定。
当主服务器进行命令传播时,不仅仅会将写命令发送给所有的从服务器,还会将写命令入队到复制积压缓冲区里面(这个大小可以调的)。如果复制积压缓冲区存在丢失的偏移量的数据,那就执行部分重同步,否则执行完整重同步。
服务器运行的ID(run ID)实际上就是用来比对ID是否相同。如果不相同,则说明从服务器断线之前复制的主服务器和当前连接的主服务器是两台服务器,这就会进行完整重同步。
所以流程大概如此:
同步的流程
2.1.3命令传播
当完成了同步之后,主从服务器就会进入命令传播阶段。这时主服务器只要将自己的写命令发送给从服务器,而从服务器接收并执行主服务器发送过来的写命令,就可以保证主从服务器一直保持数据一致了!
在命令传播阶段,从服务器默认会以每秒一次的频率,向服务器发送命令REPLCONF ACK <replication_offset>
其中replication_offset是从服务器当前的复制偏移量
发送这个命令主要有三个作用:
- 检测主从服务器的网络状态
- 辅助实现min-slaves选项
- 检测命令丢失
五、最后
画了好久好久的图,终于写完啦。