Redis 主从复制架构
1. 单机版的局限
单机版的局限性在哪里?
如果Redis
所在的实例宕机,那么此时即不支持读也不支持写,这便是单机版存在的问题,可用性和并发性都是非常有限的。
为解决上述的问题,从而引出了主从复制架构。
2. 主从复制架构分析
主从架构的示意图如下
客户端所有的写操作都是通过 Master
实例来完成,所有的读操作都是通过Slave
来完成的,从而实现读写分离。
优点
- 可用性提高。当
Master
宕机后,依然可以对Slave
读操作。当一台Slave
宕机,依然可以读其他Slave
进行读操作。 - 并发性提高。更准确的是对读的并发性有所提高,可以对多台的
slave
进行读取,同时,当业务量剧增时,随时可以增加新的Slave
。
缺点
- 可用性有限:当
Master
宕机后,此时写操作都失败,直到实例重启。 - 数据同步问题:数据从
Master
同步到Slave
时,带来的数据不一致性问题,该问题在分布式锁的环境下尤为明显。
3. 主从复制原理
slave
实例可以通过执行SLAVEOF
或设置slaveof <masterip> <masterport>
去复制master
服务器。
3.1 旧版复制功能的实现
Redis 2.8
版本以前复制的实现原理如下:
Redis
的复制功能分为同步sync
和命令传播command propagate
两个操作:
- 同步:用于将从服务器的数据库状态更新至主服务器当前时刻数据库状态一致
- 命令传播:用于主服务器的数据库状态被更改后,让主从数据库状态一致
3.1.1 同步
从服务器发送SLAVEOF
命令后,首先会执行同步操作,从服务器通过发送SYNC
命令来完成,SYNC
命令的执行步骤:
-
从服务器向主服务器发送
SYNC
命令。 -
主服务器收到
SYNC
命令后执行BGSAVE
命令,在后台生成一个RDB
文件,并使用缓冲区记录从现在以后的所有写命令(防止生成RDB
文件的同时,有新命令没有写入RDB
文件中)。 -
主服务器将
RDB
文件发送给从服务器,从服务器载入该RDB
文件。 -
主服务器将缓冲区里面的命令发送给从服务器,从服务器执行这些写命令,此时主从数据相互一致。
3.1.2 命令传播
同步操作完成后,主从实例便处于一致性状态,但是当有新的写命令写入到主实例,此时便又不一致了。
可见,通过命令传播可以使主从重新处于一致性状态。
3.1.3 旧版复制的缺陷
在从服务器第一次连接主服务器时,会进行RDB
的全量载入。但是由于网络波动,导致主从断开连接,当从服务器重新连接后,便又会重新发送SYNC
命令,进行RDB
的全量载入。如果1
分钟内掉线三次,则会进行三次全量复制,可是1
分钟内,Master
可能并不会新增很多数据,主从之间的数据差异性并不是很大,所以该方式很浪费资源。
3.2 新版复制功能的实现
为了解决主从掉线后的复制权限,Redis 2.8
使用PSYN
代替SYNC
执行同步操作。
PSYNC
具有完整重同步和部分重同步两种模式。
-
完整重同步:同
SYNC
命令的执行步骤一样 -
部分重同步:用于处理断线后重复制情况,主服务器可以将主从服务器连接断开期间执行的写命令发送给从服务器,从服务器只要接收并执行这些写命令,就可以将数据库更新至主服务器当前所处状态。
3.3 部分重同步的实现
部分重同步功能由以下三个部分构成:
- 主服务器的复制偏移量(replication offset)和从服务器的复制偏移量
- 主服务器的复制积压缓冲区(replication backlog)
- 服务器的与运行ID(run ID)
3.3.1 复制偏移量
主服务器和从服务器都维护一个复制偏移量。
- 主服务器每次向从服务器传播N个字节的数据时,就将自己的复制偏移量的值加上N。
- 从服务器每次收到主服务器传播来的N个字节的数据个给从服务器时,就将自己的复制偏移量的值加上N。
通过对比offset
的值,可以明显知道两者是否处于一致性状态。
当处于不一致状态时,便需要恢复A
丢失的数据,其是通过复制积压缓冲区实现的。
3.3.2 复制积压缓冲区
复制积压缓冲区是主服务器维护的一个固定长度、先进先出的==队列==,默认大小为 1MB。
当主服务器进行命令传播时,不仅会将命令发送给所有从服务器,还会将写命令入队到复制积压缓冲区。
复制积压缓冲区会为队列中的每个字节记录相应的复制偏移量:
当从服务器重新连接上主服务器时,会通过 PSYNC
命令将自己的复制偏移量 offset
发送给主服务器,主服务器根据这个复制偏移量来决定对从服务器执行何种同步操作:
- 如果
offset
偏移量之后的数据仍然存在于复制积压缓冲区,那么主服务器采用部分重同步。 - 否则,采用完整重同步(因为找不到写命令,只能进行全量复制,所以可以更改缓冲区的大小,使命令被保存的时间更久,这样就可以进行增量复制)。
3.3.3 服务器运行 ID
- 每个
Redis
服务器都有自己的运行ID
- 运行
ID
由服务器启动自动生成,由40
个随机的16
进制字符组成
当从服务器对主服务器进行初次复制时,主服务将自己的运行 ID
传送给从服务器,从服务器会将这个运行 ID
保存起来。
当从服务器断线重连上一个主服务器时,从服务器会向主从器发送之前保存的运行ID
。
如果运行ID
与主服务器的运行ID
相同,主服务器可以继续尝试执行部分重同步。
否则,说明主服务器不再是之前的主服务器,需要进行完整重同步操作。
当一个主服务器宕机后,那么哨兵系统会选择一个从服务器作为主服务器,此时运行ID
便不一致了。