最近由于疫情影响,时间比较多,所以开始学习之前一直想学,但是却没时间学的Redis。这两天研究了一下Redis的持久化以及主从复制机制,现在已经很晚了,就不多废话了。这篇博客就来谈一谈Redis的主从复制机制。在这里需要提醒一下,主从复制依赖于Redis的快照持久化(RDB),所以如果不了解持久化,请先去研究那一块的内容,可以看看这篇博客:详细分析Redis的持久化操作—RDB与AOF。
二、正文 2.1 什么是主从复制
首先我们来谈一谈最基本的问题——什么是主从复制,为什么需要它?我们知道,现在的应用基本上都会使用集群进行部署,同一个应用部署在多台服务器上,各台服务器互相同步,各自承担一部分任务,以此来减轻单台服务器的压力。而主从复制就是Redis用来对存储相同数据的多台服务器进行同步的机制。
假设我们只在一台服务器上部署了Redis服务器,那所有需要访问Redis服务器的请求,都需要这一台服务器来处理,这对服务器来说有很大的压力。如果访问的很频繁,那么一台服务器根本处理不过来,所以我们需要多台服务器同时部署Redis,然后每一台服务器承担一部分任务。
如果我们部署了多台Redis服务器,存储相同的数据,为同一个应用进行服务,那么不难想到,我们需要处理一个问题——数据同步。我们必须保证这多台服务器的Redis数据库中,存储的数据是一致的,而且都应该是正确的数据,否则将会导致对请求进行错误的处理,比如查询出的是过期的数据,或者对已经过期的数据进行了修改。而主从复制,就是Redis对这多台服务器进行数据同步的机制。
在主从复制机制中,Redis将服务器分为主服务器和从服务器,主服务器负责接收用户提交的修改指令,修改数据库中的数据,同时将修改同步到从服务器中,而从服务器的任务就是与主服务器进行数据同步,并分担本应该由主服务器执行的查询请求,减小主服务器的压力,除此之外,为了减轻主服务器的压力,我们也可以关闭主服务器的持久化操作,而让从服务器来进行持久化。
2.2 主从复制的实现过程
完整的主从复制包含以下两步:
同步:将从服务器当前的状态,更新为主服务器当前的状态,也就是使用主服务器中存储的数据,替换掉从服务器的数据;
命令传播:主服务器执行每一次修改操作后,都需要告知从服务器,让从服务器执行相同的操作,以保证一致性;
下面我就来分别分析一下这两个过程的详细实现。
2.3 同步的实现原理
从服务器与主服务器同步,需要使用到SYNC指令,详细的执行流程如下:
从服务器连接到主服务器,并向主服务器发送SYNC指令;
主服务器接收到SYNC指令后,开始执行BGSAVE指令(快照持久化),此时主服务器将调用fock(),创建一个子进程,子进程去生成Redis当前状态的一个快照;在这个过程中,新到达主服务器的写指令将会被记录在缓冲区;
主服务器执行完BGSAVE后,将快照文件发送给从服务器,在发送的过程中,如果还有新的写指令到达,也会继续记录在缓冲区;从服务器接收到主服务器发来的快照文件后,将丢弃自己内存中的数据,开始加载快照文件中记录的数据,加载完成后,就可以处理接收到的请求了;
主服务器在发送完快照文件后,开始将缓冲区中记录的写指令也同步到从服务器;从服务器接收到主服务器发来的指令,便依次执行这些指令,执行完后,就与主服务器的状态一致了;
2.4 命令传播的实现原理
为什么需要命令传播?这个应该很好理解。经过上面的同步后,主服务器与从服务器存储的数据就一致了,这之后,从服务器就可以分担查询操作,但是写操作还是需要主服务器完成。所以,虽然当前主从服务器已经一致,但是主服务器如果执行了一次写操作,而从服务器没有执行,它们又将变成不一致的状态。而命令传播的实现原理很简单:主服务器每次执行写操作,都会将这个写指令发送给从服务器,从服务器接收到后,也执行这个写指令,这样就能让主服务器和从服务器持续的保持一致。
有人可能会想,为什么是将指令发送到从服务器,而不是重新执行一次同步操作呢?答案很简单,因为上面的同步操作,需要很大的开销。执行BGSAVE指令创建快照,需要创建一个子进程,同时生成一个文件,需要进行大量的磁盘IO,在数据量很大的情况下,可能会使主服务器产生数毫秒甚至是一秒的停顿。而向从服务器传输一个指令的开销,要比上面的同步小得多。
2.5 部分重同步介绍