Redis主从复制数据同步实现原理详细介绍
文章目录
- 一、主从复制的概念
- 二、全量复制(完整重同步)
- 三、增量复制(部分重同步)
- 1. 增量复制的核心思想
- 2. 增量复制的实现
- 3. 复制偏移量(replicationoffset)
- 4. 复制积压缓冲区(replicationbacklog)
- 4.1 缓冲区队列内容
- 4.2 缓冲区队列更新
- 4.3 同步方式判断
- 4.4 缓冲区配置优化
- 5. 服务器的运行ID(runID)
- 四、心跳检测
- 五、关键配置参数
- 总结
Redis 为保证高可用,提供了主从服务器、集群搭建的方案。这样即使某一个服务器宕机了,Redis 还可以对外提供服务。一般主服务器提供读写功能,从服务器只提供读功能,为保证主从服务器的读一致性,需要将主服务器的数据同步到从服务器。以下是关于主从服务器实现数据同步的详细介绍:
一、主从复制的概念
Redis从2.8版本开始,使用PSYNC命令代替SYNC命令来执行复制时的同步操作。PSYNC指令分两种同步模式:全量复制(完整重同步) 和 增量复制(部分重同步) 。
Redis 主从服务器在初次连接的时候,会进行一次全量复制,当全量复制完成后会进行增量复制。slave 服务器在数据同步过程中会优先尝试增量复制,如果不满足增量复制条件,则发起全量复制。
以下是Redis 在主从复制时选择两种模式执行的流程:
二、全量复制(完整重同步)
Redis 全量复制使用PSYNC命令,通过让主服务器创建并发送RDB文件,以及向从服务器发送保存在缓冲区里面的写命令来进行同步。
以下是Redis全量复制的执行步骤:
- 从服务器先判断是否为初次复制:
- 如果是初次复制,则通知主服务器进行全量复制;
- 如果不是初次复制,则通知主服务器进行部分复制,但是主服务器判断无法进行部分复制,最后主服务器会自己选择执行全量复制。
- 主服务器收到全量复制命令后,执行BGSAVE命令,在后台生成一个RDB文件,并使用一个缓冲区记录从现在开始执行的所有写命令。
- 当主服务器的BGSAVE命令执行完毕时,主服务器会将BGSAVE命令生成的RDB文件发送给从服务器,从服务器接收并载入这个RDB文件,将自己的数据库状态更新至主服务器执行BGSAVE命令时的数据库状态。
- 主服务器将记录在缓冲区里面的所有写命令发送给从服务器,从服务器执行这些写命令,将自己的数据库状态更新至主服务器数据库当前所处的状态。
- 如果从服务器开启了AOF,则会触发bgrewriteaof的执行,从而保证AOF文件更新至主服务器数据库的最新状态。
三、增量复制(部分重同步)
Redis 增量复制主要目的是解决主从服务器断线重连后的 增量数据,避免全量复制的开销。
1. 增量复制的核心思想
当从服务器在断线后重新连接主服务器时,主服务器可以将主从服务器连接断开期间执行的写命令发送给从服务器,从服务器只要接收并执行这些写命令,就可以将数据库更新至主服务器当前所处的状态。
2. 增量复制的实现
增量复制同步功能的实现由以下三个部分构成:
- 主服务器的复制偏移量(replicationoffset)和从服务器的复制偏移量。
- 主服务器的复制积压缓冲区(replicationbacklog)。
- 服务器的运行ID(runID)。
3. 复制偏移量(replicationoffset)
执行复制的主服务器和从服务器会分别维护一个复制偏移量:
- 主服务器每次向从服务器传播N个字节的数据时,就将自己的复制偏移量的值加上N。
- 从服务器每次收到主服务器传播来的N个字节的数据时,就将自己的复制偏移量的值加上N。
假设当前主从服务器的复制偏移量的值都为10086,如果这时主服务器向三个从服务器传播长度为33字节的数据,那么主服务器的复制偏移量将更新为10086+33=10119,而三个从服务器在接收到主服务器传播的数据之后,也会将复制偏移量更新为10119。
主从服务器通过维护复制偏移量,比较复制偏移量的大小,就可以判断主从服务器是否处于一致状态:
- 如果主从服务器处于一致状态,那么主从服务器两者的偏移量总是相同的。
- 相反,如果主从服务器两者的偏移量并不相同,那么说明主从服务器并未处于一致状态。
4. 复制积压缓冲区(replicationbacklog)
复制积压缓冲区是由主服务器维护的一个固定长度(fixed-size)先进先出(FIFO)队列,默认大小为1MB。
4.1 缓冲区队列内容
主服务器的复制积压缓冲区里面会保存着一部分最近传播的写命令,并且复制积压缓冲区会为队列中的每个字节记录相应的复制偏移量。
4.2 缓冲区队列更新
当主服务器进行命令传播时,它不仅会将写命令发送给所有从服务器,还会将写命令入队到复制积压缓冲区里面。由于队列是固定长度,所以队列内保存的命令在不断的更新。
如果主从服务器断开时间很久,主从服务器的复制偏移量可能会相差很大,从服务器的复制偏移量可能已经不再缓冲区了。
4.3 同步方式判断
当从服务器重新连上主服务器时,从服务器会通过PSYNC命令将自己的复制偏移量offset发送给主服务器,主服务器会根据这个复制偏移量来决定对从服务器执行何种同步操作:
- 如果offset偏移量之后的数据(也即是偏移量offset+1开始的数据)仍然存在于复制积压缓冲区里面,那么主服务器将对从服务器执行增量复制操作。
- 相反,如果offset偏移量之后的数据已经不存在于复制积压缓冲区,那么主服务器将对从服务器执行全量复制操作。
4.4 缓冲区配置优化
Redis为复制积压缓冲区设置的默认大小为1MB,如果主服务器需要执行大量写命令,又或者主从服务器断线后重连接所需的时间比较长,那么这个大小也许并不合适。如果复制积压缓冲区的大小设置得不恰当,那么PSYNC命令的复制重同步模式就不能正常发挥作用,因此,正确估算和设置复制积压缓冲区的大小非常重要。
优化配置复制积压缓冲区大小repl-backlog-size
的值,该值最小大小可以根据公式 2*second*writesizeper_second
来计算:
- second为从服务器断线后重新连接上主服务器所需的平均时间(以秒计算)。
- write_size_per_second则是主服务器平均每秒产生的写命令数据量(协议格式的写命令的长度总和)。
5. 服务器的运行ID(runID)
除了复制偏移量和复制积压缓冲区之外,实现增量复制还需要用到服务器运行ID(runID):
- 每个Redis服务器,不论主服务器还是从服务,都会有自己的运行ID。
- 运行ID在服务器启动时自动生成,由40个随机的十六进制字符组成,例如53b9b28df8042fdc9ab5e3fcbbbabff1d5dce2b3。
- 当从服务器对主服务器进行初次复制时,主服务器会将自己的运行ID传送给从服务器,而从服务器则会将这个运行ID保存起来。
- 当从服务器断线并重新连上一个主服务器时,从服务器将向当前连接的主服务器发送之前保存的运行ID:
- 如果从服务器保存的运行ID和当前连接的主服务器的运行ID相同,那么说明从服务器断线之前复制的就是当前连接的这个主服务器,主服务器可以继续尝试执行增量复制操作。
- 相反地,如果从服务器保存的运行ID和当前连接的主服务器的运行ID并不相同,那么说明从服务器断线之前复制的主服务器并不是当前连接的这个主服务器,主服务器将对从服务器执行全量复制操作。
四、心跳检测
在命令传播阶段,从服务器默认会以每秒一次的频率,向主服务器发送命令:
# replication_offset是从服务器当前的复制偏移量。
REPLCONF ACK <replication_offset>
从服务器发送REPLCONF ACK命令对于主从服务器有三个作用:
- 检测主从服务器的网络连接状态:
- 如果主服务器超过一秒钟没有收到从服务器发来的REPLCONF ACK命令,那么主服务器就知道主从服务器之间的连接出现问题了。
- 通过向主服务器发送INFO replication命令,在列出的从服务器列表的lag一栏中,我们可以看到相应从服务器最后一次向主服务器发送REPLCONF ACK命令距离现在过了多少秒。
- 辅助实现min-slaves选项:
- Redis的min-slaves-to-write和min-slaves-max-lag两个选项可以防止主服务器在不安全的情况下执行写命令。
- 比如我们向主服务器设置min-slaves-to-write=3和min-slaves-max-lag=10,那么在从服务器的数量少于3个,或者三个从服务器的延迟(lag)值都大于或等于10秒时,主服务器将拒绝执行写命令,这里的延迟值就是上面提到的INFO replication命令的lag值。
- 检测命令丢失:
- 如果因为网络故障,主服务器传播给从服务器的写命令在半路丢失,那么当从服务器向主服务器发送REPLCONF ACK命令时,主服务器将发觉从服务器当前的复制偏移量少于自己的复制偏移量,然后主服务器就会根据从服务器提交的复制偏移量,在复制积压缓冲区里面找到从服务器缺少的数据,并将这些数据重新发送给从服务器。
- 注意,主服务器向从服务器补发缺失数据这一操作的原理和增量复制操作的原理非常相似,这两个操作的区别在于,补发缺失数据操作在主从服务器没有断线的情况下执行,而部分重同步操作则在主从服务器断线并重连之后执行。
五、关键配置参数
参数 | 作用 | 推荐值 |
---|---|---|
repl-backlog-size | 调整复制积压缓冲区大小 | 2 * 网络延迟 * 每秒写入量 |
repl-diskless-sync | 启用无盘复制,减少磁盘 I/O | yes (网络良好时) |
repl-diskless-sync-delay | 无盘复制延迟时间(秒) | 5 |
client-output-buffer-limit slave | 限制复制缓冲区大小,防止OOM | 512mb 128mb 60 |
repl-timeout | 复制超时时间 | 60s (需大于repl-ping-replica-period ) |
replica-serve-stale-data | 断线时是否允许从节点响应读请求 | no |
replicaof <master_ip> <master_port> | 指定主节点地址 | 无 |
总结
Redis主从复制通过全量复制确保初始一致性,增量复制优化持续同步效率,结合复制积压缓冲区和偏移量跟踪机制,实现了高效且可靠的数据同步。合理配置参数和监控网络状态是优化复制性能的关键。