今天讲一下多机数据库的实现。
假设现在有两个Redis服务器,地址分别为127.0.0.1:6379和127.0.0.1:12345,如果我们向服务器127.0.0.1:12345发送以下命令127.0.0.1:12345: SLAVEOF 127.0.0.1 6379
,那么12345将成为6379的从服务器。
旧版复制功能的实现
Redis的复制功能分为同步sync和命令传播command propagate两个操作:
同步
从服务器对主服务器的同步操作需要通过向主服务器发送SYNC命令来完成,以下是SYNC命令的执行步骤:
- 从服务器向主服务器发送SYNC命令
- 收到SYNC命令的主服务器执行BGSAVE命令,在后台生成一个RDB文件,并使用一个缓冲区记录从现在开始执行的所有写命令。
- 当主服务器的BGSAVE命令执行完毕时,主服务器会将BGSAVE命令生成的RDB文件发送给从服务器,从服务器接收并载入这个RDB文件,将自己的数据库状态更新至主服务器执行BGSAVE命令时的数据库状态。
- 主服务器将记录在缓冲区里面的所有写命令发送给从服务器,从服务器执行这些写命令,将自己的数据库状态更新至主服务器数据库当前所处的状态。
命令传播
主服务器会将自己执行的写命令发送给从服务器执行,当从服务器执行了相同的写命令之后,主从服务器将再次回到一致状态。
旧版复制功能的缺陷
旧版复制功能对于断线后重复制,采用的是跟初次复制一样的策略,导致断线重复制成本非常高。
新版复制功能的实现
Redis从2.8版本开始,使用PSYNC命令代替SYNC命令来执行复制时的同步操作。
PSYNC命令具有完整重同步和部分重同步两种模式:
- 完整重同步和初次复制一样,让主服务器创建并发送RDB文件,以及向从服务器发送保存在缓冲区里面的写命令来进行同步。
- 部分重同步则用于处理断线后重复制情况。
部分重同步的实现
部分重同步功能由以下三个部分构成
- 主服务器的复制偏移量和从服务器的复制偏移量
- 主服务器的复制积压缓冲区
- 服务器的运行ID
复制偏移量
执行复制的双方-主服务器和从服务器会分别维护一个复制偏移量
- 主服务器每次向从服务器传播N个字节的数据时,就将字节的复制偏移量的值加上N
- 从服务器每次收到主服务器传播来的N个字节的数据时,就将字节的复制偏移量的值加上N
- 对比主从服务器的复制偏移量,程序可以很容易地知道主从服务器是否处于一致状态。
复制积压缓冲区
复制积压缓冲区是由主服务器维护的一个固定长度先进先出队列,默认大小为1MB。
当从服务器重新连上主服务器时,从服务器会通过PSYNC命令将自己的复制偏移量offset发送给主服务器,主服务器会根据这个复制偏移量来决定对从服务器执行何种同步操作。要么是完全重同步,要么是部分重同步
服务器运行ID
- 每个Redis服务器,不论主从,都会有自己的运行ID
- 在服务器启动时自动生成,由40个随机的十六进制字符组成
当从服务器对主服务器进行初次复制时,主服务器会将自己的运行ID传送给从服务器,而从服务器则会将这个运行ID保存起来。
心跳检测
在命令传播节点,从误区默认会以每秒一次的频率才,向主服务器发送命令:REPLCONF ACK <replication_offset>
,其中replication_offset是从服务器当前的复制偏移量,主要有三个作用:
- 检测主从服务器的网络连接状态
- 辅助实现min-slaves选项
- 检测命令丢失