十七、Redis进阶-Redis主从复制原理
主从复制原理
1)当启动一个从数据库后,从数据库会向主数据库发送SYNC
命令
2)与此同时,主数据库接收到SYNC
命令后开始在后台保存快照(RDB持久化的过程),并将保存快照期间接收的命令缓存起来。快照完成后,Redis会将快照文件和所有缓存的命令发送给从数据库
3)从数据库收到后,会载入快照文件并执行到缓存的命令。
以上过程是复制的初始化。复制初始化结束后,主数据库每当收到写命令时就会将命令同步给从数据库,从而保证主从数据库一致。
读写分离一致性
通过复制可以实现读写分离,可以提高服务器的负载能力。读频率大于写频率的应用场景中,当单机Redis无法应付大量的读请求时,可以通过复制功能建立多个从数据库节点,主数据库只进行写操作,而从数据库负责读操作。
从数据库持久化
持久化是比较耗时的操作,为了提高性能,可以通过复制功能建立一个或多个从数据库,并在从数据库中开启持久化,同时主数据库中禁用持久化。当从数据库化崩溃重启后主数据库会自动将数据同步过来,因此不用担心数据丢失。
如果主数据库崩溃时,情况就变得复杂很多。手工通过从数据库恢复主数据库数据时,需要严格按照下面两步操作:
1)在从数据库中使用replicaof no one
命令将从数据库提升成主数据库继续服务;
2)启动之前崩溃的主数据库,然后使用replicaof
命令将其设置成新的主数据库的从数据库,即可将数据同步回来。
无硬盘复制
主从复制是基于RDB方式的持久化实现的,主数据库端在后台保存RDB快照,从数据库端则接收并载入快照文件。这样实现的优点是简化逻辑,复用已有的代码,但是缺点也很明显,如下:
1)主数据库禁用RDB快照时,如果执行了复制初始化操作,Redis依旧会生成RDB快照,因此下次启动后主数据库会以该快照恢复数据。因为复制发生的时间不确定,这使得恢复的数据可能是任何时间点
2)复制初始化时需要在硬盘中创建RDB快照文件,所以如果硬盘性能很慢时这一过程会对性能产生影响。举个栗子:把Redis作为缓存系统时,不需要持久化,服务器的硬盘读写速度可能较差。当该缓存系统使用一主多从的集群架构时,每次和从数据库同步时,Redis都会执行一次快照,同时对硬盘进行读写,导致性能降低。
增量复制
当主从数据库连接断开后,从数据库会发送SYNC
命令重新进行一次完整复制操作。这样即使断开期间数据库变化很小,也需要将数据库中的所有数据重新快照并传送一次。
增量复制基于以下三点实现:
1)从数据库会存储主数据库运行ID(run id)。每个Redis运行实例都会拥有一个唯一的运行ID,每当实例重启就会自动生成一个新的运行ID
2)在复制同步阶段,主数据库每将一个命令传送给从数据库时,都会同时把该命令存放到一个积压队列(backlog)中,并记录下当前积压队列中存放的命令的偏移量范围
3)从数据库接收到主数据库传来的命令时,会记录下该命令的偏移量
这三点是实现增量复制的基础。当主从连接准备就绪后,从数据库会发送一条PSYNC
命令来告诉主数据库可以开始把所有的数据同步过来。格式为PSYNC 主数据库的运行ID 断开前最新的命令偏移量
1)首先,主数据库会判断从数据库传送来的运行ID是否和自己运行的ID相同。此步骤是为了确保从数据库之前确实是和自己同步的,以免从数据库拿到错误的数据
2)其次,判断从数据库最后同步成功的命令偏移是否在积压队列中,如果在可则可以执行增量复制,并将积压队列中相应的命令发送给从数据库
**积压队列本质上是一个固定长度的循环队列。**默认情况下积压队列的大小为1MB,可以通过配置文件repl-backlog-size
选项来调整。
积压队列越大,允许的主从数据库断线的时间就越长。