redis集群中的从服务器同步主服务器上的数据称之为:复制。
一、旧版复制功能的实现(2.8以前)
redis的复制功能分为同步(sync)和命令传播(command propagate)两个操作。
>同步:将从服务器的数据库状态更新至主服务器当前所处的数据库状态。
>命令传播:用于在主服务器的数据库状态被修改,导致主从服务器的数据库状态出现不一致时,让主从服务器的数据库重新回到一致状态。
1.1 同步
从服务器对主服务器的同步操作需要通过向主服务器发送sync命令来完成,以下是sync命令的执行步骤:
1)从服务器向主服务器发送sync命令
2)手动sync命令的主服务器执行BGSAVE命令,在后台生成一个RDB文件,并使用一个缓冲区记录从现在开始执行的所有写命令。
3)当主服务器的BGSAVE命令执行完毕时,主服务器会将BGSAVE命令生成的RDB文件发送给从服务器,从服务器接收并载入这个RDB文件,将自己的数据库状态更新至主服务器执行BGSAVE命令时的数据库状态。
4)主服务器将记录在缓冲区里面的所有写命令发送给从服务器,从服务器执行这些写命令,将自己的数据库状态更新至主服务器数据库当前所处的状态。
1.2 命令传播
在同步操作执行完毕之后,主从服务器两者的数据库将达到一致状态,但这种一致状态不是一成不变的,每当主服务器执行客户端发送的写命令时,主服务器的数据库就有可能会被修改,并导致主从服务器状态不再一致。
为了让主从服务器再次回到一致状态,主服务器需要对从服务器执行命令传播操作:主服务器会将自己执行的写命令,发送给从服务器执行,当从服务器执行完这个命令之后,主从服务器将再次回到一致状态。
1.3 关于sync的性能
先说结论:非常耗费资源。每次执行sync命令,主从服务器需要执行以下动作:
>主服务器需要执行BGSAVE命令来生成RDB文件,这个生成操作会耗费主服务器大量的CPU、内存和磁盘IO资源。
>主服务器需要将自己生成的RDB文件发送给从服务器,这个发送操作会耗费主从服务器大量的网络资源,并对主服务器响应命令请求的时间产生影响。
>接收到RDB文件的从服务器需要载入主服务器发来的RDB文件,并且在载入期间,从服务器会因为阻塞而没有办法处理命令请求。
二、旧版复制功能的缺陷
在redis2.8以前,从服务器对主服务器的复制可以分为以下两种情况:
>初次复制:从服务器以前没有复制过任何主服务器,或者从服务器当前要复制的主服务器和上次复制的主服务器不同。
>断线后重复制:处于命令传播阶段的主从服务器因为网络原因而中断了复制,但从服务器通过自动重连接重新连上了住服务器,并重新进行一遍同步复制,即sync复制。在这种情况下,为了让从服务器补足一小部分缺失的数据,却要让主从服务器重新执行一次sync命令,这种做法无疑是非常低效的。
三、新版复制功能的实现
Redis2.8以后通过psync命令代替sync命令来执行复制时的同步操作,以解决旧版复制功能在处理断线重复制情况时的低效问题。
psync命令具有完全重同步(full resynchronization)和部分重同步(partial resynchronization)两种模式:
>完全重同步用于处理初次复制情况:完全重同步的执行步骤和sync命令的执行步骤基本一样,它们都是通过让主服务器创建并发送RDB文件,以及向从服务器发送保存在缓冲区里面的写命令来进行同步。
>部分重同步用于处理断线后重复复制的情况:当从服务器在断线后重新连接主服务器时,主服务器会将主从服务器连接期间执行的写命令发送给服务器,从服务器只要接收并执行这些写命令,就可以将数据库更新至主服务器当前所处的状态。
对比一下sync命令和psync命令处理断线重复复制的方法,虽然sync命令和psync命令都可以让断线的主从服务器重新回到一致状态,但执行部分重同步所需的资源比起执行sync命令所需的资源要少得多,完成同步的速度也快得多。执行sync命令需要生成、传送和载入整个RDB文件,而部分重同步只需要将从服务器缺少的命令发送给从服务器执行就可以了。