引言
??在了解了Redis的底层结构以及持久化机制后,就可以开始学习Redis主从复制的原理了。 ??Redis中,通过SLAVEOF命令或者slaveof选项设置就可以实现一个服务器复制另一服务器。 ??Redis2.8版本以前复制为旧版,2.8开始使用新版复制功能。 ??Redis中,从服务器对主服务器的复制可以分两种情况:
- 初次复制:从服务器以前没有复制过任何主服务器,或者从服务器当前要复制的主服务器和上一次复制的主服务器不同
- 断线后复制:处于命令传播阶段的主从服务器因为网络原因而中断了复制,但从服务器通过自动重连重新连上了主服务器,并继续复制主服务器
一、旧版复制
??旧版复制功能分为:同步(sync)、命令传播(command propagate)两个部分:
- 同步:用于将从服务器数据库状态更新至主服务器的数据库状态
- 命令传播:用于主服务器数据库状态修改导致主从数据库状态不一致时,让主从服务器数据库状态一致
1、同步
??从服务器向主服务器发送SYNC命令即开始进行同步,步骤如下:
- 从服务器向主服务器发送SYNC命令
- 主服务器收到命令后,执行BGSAVE命令后台生成RBD文件,并使用一个缓冲区记录从现在开始之后的写命令
- 主服务器生成完RDB文件后,发送给从服务器;从服务器接收该RDB并更新
- 主服务器将记录在缓冲区的所有写命令发送给从服务器,从服务器更新至主服务器当前所处的数据库状态
??下图展示了SYNC期间主从的通信过程:
2、命令传播
??在主服务器执行了写命令后,主从服务器数据库状态又变成不一致。为了让主从服务器再次回到一致状态,主服务器会执行命令传播操作:将造成主从服务器不一致的那条写命令,发送给从服务器执行。
3、旧版复制缺陷
??对于初次复制来说,旧版能够很好地完成任务;但对于断线后复制来说,旧版复制功能效率低。因为,断线重连后旧版执行的复制,是执行SYNC命令让主服务器生成RDB文件来进行全量复制。一个断线重连的例子如下图: ??可以发现,断线重连所造成的的数据库状态不一致,只需要执行中断期间主服务器执行的写命令(图中的T10088~T10090)即可让主从数据库状态回到一致,而实际则通过生成整个RDB来进行同步,这样就导致执行了很多不需要同步的写命令。
二、新版复制
??新版复制命令使用PSYNC命令来代替SYNC执行复制时的同步操作。 ??PSYNC命令分为两种模式:完整重同步(full resynchronizaiton)和部分重同步(partail resynchronization)。
完整重同步:用于初次复制的情况,执行步骤与SYNC命令基本一样,都是让主服务器生成并发送一个RDB文件,以及向从服务器发送保存在缓冲区里面的写命令 部分重同步:用于处理断线重连后复制的情况,断线重连后,如果条件允许,主服务器可以将断开期间执行的写命令发送给从服务器,从服务器只要接收并执行这些写命令,即可将数据库状态更新到与主服务器一致
??一个新版复制的例子如下:
1、完整重同步
??完整重同步步骤基本与SYNC命令复制步骤一致。
2、部分重同步
??部分重同步功能由三个部分组成:
- 主服务器的复制偏移量和从服务器的复制偏移量
- 主服务器的复制积压缓冲区
- 服务器的运行ID(run ID)
??复制偏移量:主服务器和从服务器会各自维护一个复制偏移量。主服务器每次向从服务器传播N个字节数据时,就将自己的复制偏移量加N;从服务器接收到N个字节数据后,就将自己的复制偏移量加N。 ??复制积压缓冲区:由主服务器维护的一个固定长度的先进先出队列,默认1MB。当命令传播时,不仅会将写命令发送给所有从服务器,还会将该命令写入复制积压缓冲区。
从服务器重连上主服务器时,会通过PSYNC命令将自己的复制偏移量offset发送给主服务器。主服务器根据这个复制偏移量来进行判断: ??1、如果offset之后的数据(即offset+1开始的数据)在复制积压缓冲区中,执行部分重同步操作 ??2、如果数据不在复制积压缓冲区中,则执行完整重同步操作
??服务器运行ID:不论主从服务器,每个服务器都有自己的运行ID,这个ID是在启动的时候自动生成的。实现部分重同步的时候也需要用到服务器运行ID。
当从服务器重连上主服务器时,从服务器会向当前主服务器发送之前保存的主服务器运行ID:当该运行ID与当前连接的主服务器运行ID相同时,说明断线之前复制的就是这个主服务器,主服务器就可以尝试执行部分重同步操作;相反,如果运行ID不同,则主服务器将对从服务器执行完整重同步操作
??新版的复制流程如下图:
3、命令传播
??与旧版命令传播一致。
三、命令传播中的心跳检测
??命令传播阶段,从服务器默认以每秒一次的频率,向主服务器发送REPLCONF ACK <replication_offset> 。replication_offset为当前从服务器的复制偏移量。 ??发送REPLCONF ACK主要有三个作用:检测主服务器的网络连接状态、辅助实现min-slaves选项、检测命令丢失。 ??检测主服务器的网络连接状态: 主从服务器可以通过REPLCONF ACK命令来判断两者之间的连通性。如果主服务器超过一秒没有收到从服务器发来的REPLCONF ACK命令,那么主服务器就知道与该从服务器之间的连接出现了问题。通过向主服务器发送INFO replication ,在从服务器列表的lag一栏可以看出距离上一次从服务器发送REPLCONF ACK命令过去了多久(单位:秒)。一般情况下,lag值为0或1。 ??辅助实现min-slaves选项: Redis的min-slaves-to-write 和min-slave-max-lag 两个选项可以防止主服务器在不安全的情况下执行写命令。 ??检测命令丢失: 主服务器发觉从服务器当前的复制偏移量少于自己的复制偏移量,就会根据从服务器发送过来的复制偏移量,在复制积压缓冲区中查找并发送缺少的数据。
总结
1、Redis2.8版本以前为旧版复制,2.8或以上使用新版复制 2、旧版处理断线后重复制效率低,新版部分重同步功能解决了这个问题 3、旧版复制功能使用SYNC命令,分为同步和命令传播两个部分;新版使用PSYNC命令,同步分为完整重同步、部分重同步两种,命令传播与旧版一致 4、部分重同步通过复制偏移量、复制积压缓冲区、服务器运行ID三个部分实现 5、命令传播用于检测主服务器的网络连接状态、辅助实现min-slaves选项、检测命令丢失
|