Redis的复制主要为两部分:同步和命令传播
- 同步:将从服务器的数据库状态与主服务器保持一致.
- 命令传播:用于在主服务器的数据被修改后,让从服务器的数据与主服务器保持一致.
以上和本篇内容都参考于《Redis设计与实现》
,但我觉得同步和命令传播两者本质都是数据同步,只不过前者是全量同步,后者是增量同步。
复制功能的旧版实现
- 同步
- 主服务器接受从服务器的
SYNC
命令后执行BGSAVE
命令,在后台生成一个RDB
文件,并使用一个缓冲区记录从此刻开始执行的所有写命令 - 主服务器
BGSAVE
执行完毕后,将生成的RDB
文件和缓冲区积累的写命令发送给从服务器,从服务器加载该文件达到全量同步主服务器的目的
- 主服务器接受从服务器的
- 命令传播
- 主服务器后续会将写命令发送给从服务器执行,以达到增量同步的目的
- 缺点
- 对于初次复制能很好完成任务,但对于断线后重新复制,因为其没有机制可以判断主从之间不同步的数据偏移,所以只能向主服务器发送SYNC命令执行一次全量同步,会导致无用的资源耗费
复制功能的新版实现
- 新版功能的复制主要是解决了断线重复制时的低效问题。为了解决该问题,Redis从2.8版本开始,使用
PSYNC
命令代替SYNC
命令来执行复制时的同步操作 - PSYNC具体
完整重同步
和部分重同步
两种模式- 完整重同步:与旧版本的同步操作一样,通过一个完整的RDB文件+主服务器缓冲区的写命令实现同步
- 部分重同步:主服务器可以将主从断开期间执行的写命令都发给从服务器,从服务器只要接受并执行这些命令,便可与主服务器的状态保持一致
部分重同步的实现
- 其主要由三个部分实现:
复制偏移量
,复制积压缓冲区
,运行ID
- 复制偏移量
- 主从双方都会维护一个复制偏移量,当主服务器传出N个字节的数据或者从服务器收到N个字节的数据时,都会将自己的复制偏移量加上N
- 通过对比主从的复制偏移量,可以得知数据是否一致且主从数据的数据
- 但只靠复制偏移量,无法判断执行
完整重同步
还是部分重同步
,以及偏移量差异这段数据内容也无从得知,这些都是复制积压缓冲区
实现的
- 复制积压缓冲区
- 复制积压缓冲区是由主服务器维护的一个固定长度(fixed-size)先进先出(FIFO)队列,默认大小为1MB
- 当主服务器
命令传播
时除了会把命令发给从服务器,还会写到复制积压缓冲区 - 缓冲区的实现是一个kv对形式的list,偏移量对应着具体的字节值,slave服务器连上master后,slave服务器会通过PSYNC命令将offset发送给主服务器
- 如果offset之后的数据不在缓冲区则执行完整重同步操作,反之则执行部分重同步
- 运行ID
- 每个Redis服务器,无论主从都会有一个由40个随机十六进制字符组成的运行ID
- 主服务器的运行ID会存放在从服务器上。断线重连后,从服务器会根据之前保持的运行ID是否与主服务器的一致判断主服务器是否变更,如果发生变更了则执行完整重同步,反正则执行部分重同步
心跳检测
- 在
命令传播
阶段,从服务器会默认以每秒一次的频率,向主服务器发送命令:REPLCONF ACK <replication_offset>
,其作用是:- 检测主从服务器的网络连接状态
- 辅助实现min-slaves选项
- 检测命令丢失