Redis主从复制详解
比如我们有两个Redis服务器,一个为127.0.0.1:6379和127.0.0.1:12345。如果我们向服务器127.0.0.1:12345发送这样的命令:
则127.0.0.1:12345将成为127.0.0.1:6379的从服务器,而127.0.0.1:6379则会成为主服务器。
现在我们在主服务器上执行如下命令:
在从服务器上上执行:
可以看到主从两个服务器的数据库保存的是相同的数据。我们把这种现象称为“数据库状态一致”或者简称“一致”。
我们在主服务器上执行删除操作:
然后从服务器上的数据也没有了:
复制功能的实现
Redis复制功能分为同步(sync)和命令传播(command propagate)两个操作:
同步操作用于将从服务器的数据库状态更新至主服务器当前所处的数据库状态。
命令传播操作则用于在主服务器的数据库状态被修改,导致主从服务器的数据库状态出现不一致时,让主从服务器的数据库重新回到一致状态。
同步
当客户端向服务器发送SLAVEOF的命令时,要求从服务器复制主服务器时,从服务器首先执行同步操作,也就是将从服务器的数据库状态更新至主服务器当前所处的数据库状态。
从服务器对主服务器的同步操作需要向主服务器发送SYNC命令来完成,看一下SYNC命令的执行步骤:
命令传播
在同步操作执行完毕之后,主从服务器两者的数据库将达到一致状态,但这种一致并不是一成不变的,每当主服务器执行客户端发送的写命令时,主服务器的数据库就有可能被修改,导致主从服务器状态不再一致。
为了让主从服务器再次回到一致状态,主服务器需要对从服务器执行命令传播操作:
主服务器会将自己执行的写命令,也就是那些造成主从服务器状态不一致的命令,发送给从服务器执行,当从 服务器执行了相同的写命令之后,主从服务器将再次回到一致状态。
旧版复制功能的缺陷
在Redis中,从服务器对主服务器的复制可以分为以下两种情况:
初次复制:从服务器以前没有复制过任何主服务器,或者从服务器当前要复制的服务器和上次复制的不是同一个主服务器。
断线后重复制:处于命令传播阶段的主从服务器因为网络原因中断了复制,但从服务器通过自动重连接连上了主服务器,并继续复制主服务器。
对于初次复制来说,旧版复制功能能够很好地完成任务,但是断线后重复制地效率就很低了。
在从服务器断线后重新连接上主服务器后,由于主从服务器地状态不再一致,从服务器向主服务器发送SYNC命令,而主服务器会生成当前状态地RDB文件传送给从服务器。但可能实际上从服务器缺失地只是几条命令,大多数数据和以前都是一样地。毫无疑问这样地同步效率非常低。
新版复制功能的实现
为了解决旧版复制功能再处理断线重复制情况时的低效问题,Redis从2,8版本开始使用PSYNC命令代替SYNC命令来执行复制时的同步操作。
PSYNC命令具有完整重同步(full resynchronization)和部分重同步(partial resynchronization)两种模式:
完整重同步和SYNC命令执行步骤基本一样
部分重同步则用于处理断线后重复制的情况,如果条件允许,主服务器可以将主从服务器连接断开期间执行的写命令发送给从服务器,从服务器只要接收并执行这些写命令,就可以将数据库更新至主服务器当前所处的状态。
部分重同步的实现
部分重同步功能由以下三个部分构成:
主服务器的复制偏移量和从服务器的复制偏移量
主服务器的复制积压缓冲区
服务器的运行ID(run ID)
复制偏移量
主从服务器会分别维护一个复制偏移量
主服务器每次向从服务器传播N个字节的数据时,就将自己的复制偏移量加上N
从服务器每次收到主服务器传播来的N个字节的数据,就将自己的复制偏移量加上N
通过 对比主从服务器的复制偏移量,程序就可以很容易知道主从服务器是否处于一致状态
复制积压缓冲区
复制积压缓冲区是由主服务器维护的一个固定长度的先进先出队列,默认大小为1MB(可以根据实际情况设置)
主服务器的复制积压缓冲区里面会保存这一部分最近传播的写命令,并且复制积压缓冲区会为队列中的每个字节记录相应的复制偏移量。
当从服务器重新连上主服务器时,从服务器通过PSYNC命令将自己的复制偏移量offset发送给主服务器,主服务器根据复制偏移量来决定主从服务器执行何种同步操作
服务器运行ID
每个Redis服务器,不论是主服务器还是从服务器,都会有自己的运行ID
当从服务器对主服务器进行初次复制时,主服务器会将自己的运行ID传送给从服务器,而从服务器则会将这个运行ID保存起来,在以后断线重连时向主服务器发送ID查看主服务器是否改变来决定同步策略。
PSYNC执行步骤
复制过程:
1.设置主服务器的地址和端口
2.建立套接字连接
3.发送PING命令保证连接可用
4.身份验证
5.发送端口信息
6.同步
心跳检测
在命令传播阶段,从服务器会以每秒一次的频率向主服务器发送命令
其中replication_offset是从服务器当前的复制偏移量
总结: