在Redis中可以通过SLAVEOF(5.0版本以后可使用REPLICAOF)命令让一个服务器去复制另一个服务器。被复制的服务器被称为主服务器,对主服务器进行复制的服务器成为从服务器。Redis进行主从同步的过程如下:
建立套接字连接
使用以下命令时
1 | SLAVEOF 127.0.0.1 6379 |
服务器会将IP地址127.0.0.1和6379端口保存到redisServer结构体之中。在执行完成之后,服务器根据命令所设置的IP地址以及端口,创建套接字连接。
如果套接字成功连接,那么主服务器将会为该套接字创建对应的客户端状态,并将从服务器看作一个连接到主服务器的客户端来对待。从服务器会为套接字关联一个用于处理复制工作的文件事件处理器,处理后续的复制工作,比如接受RDB文件,接受主服务器传来的写命令等等。
发送PING命令
在创建完成套接字以后,从服务器会像主服务发送一个PING请求,这个PING请求的作用有
- 检查套接字的读写状态是否正常。
- 检查主服务器是否可以正常处理命令请求。
如果主服务器返回了PONG,说明网络状态正常并且主服务器可以正常处理请求,从服务器可以继续执行下个步骤。如果出现了回复超市或者主服务器返回了一个错误,从服务器会断开连接并且尝试重连主服务器。
身份验证
在返回PONG之后,下一步决定是否进行身份验证。如果主从服务器都没有设置密码或者主从服务器设置了相同的密码,那么直接进入下一步。否则如果,主从服务器设置了不同的密码或者一个设置了密码一个没有设置,那么会身份验证失败,进行重试或者退出。
发送端口信息
在完成身份验证以后,从服务器将向主服务器发送从服务器的监听端口号。主服务器接收到该请求以后,会将端口号记录在客户端状态下的slave_listening_port属性中。
同步
在这一步中,从服务器会向主服务发送同步命令,执行同步操作,将自己的数据库更新为主数据库当前所处的状态。可以通过SYNC和PSYNC两种命令来实现主从同步。
SYNC命令
SYNC命令实现
SYNC命令的执行步骤如下:
从服务器向主服务器发送SYNC命令
收到SYNC命令的主服务器执行BGSAVE命令,生成RDB文件,同时创建一个缓冲区记录从现在开始执行的所有写命令。
当BGSAVE命令执行完毕之后,主服务器会将RDB文件发送给从服务器,从服务器载入该RDB文件,将数据库状态更新至执行BGSAVE命令时的数据库状态。
主服务器将记录在缓冲区的所有写命令发送给从服务器,从服务器执行这些命令,更新至主服务器当前所处的状态。
SYNC命令的缺陷
在出现断线后重新复制的情况时,SYNC命令的效率十分低。因为在断线后重连时,主从服务器的大部分数据是一致,从服务器将自己更新为主服务器的状态时,只需要更新中断期间的数据即可。SYNC命令没有利用好这些特性,导致了需要进行全量的RDB备份才能保持数据一致,因此Redis引入了PSYNC命令来代替SYNC命令。
PSYNC命令
PSYNC具有完整重同步和部分重同步两种模式,其中完整重同步用于处理初次复制的情况,部分重同步用于处理断线后的重复制情况。完全重同步的过程与SYNC命令的实现类似,部分重同步模式解决了SYNC模式的缺陷。部分重同步的功能有以下三个部分组成
复制偏移量
执行复制的双方会分别维护一个复制偏移量。当主服务器每次向从服务器传播N个字节的数据时,就将自己的复制偏移量加上N。从服务器接收到N个字节的数据时,也将自己的复制偏移量加上N。通过对比两者的复制偏移量,可以得出两者的数据是否一致。
复制积压缓冲区
复制积压缓冲区是一个由主服务器维护的一个固定长度的先进先出的队列,默认大小为1MB。当主服务器进行命令传播时,会将写命令入队到复制积压缓冲区之中,同时记录队列中每个字节记录的相应的复制偏移量。
当从服务器重新连接上主服务器的时候,从服务器会将自己的复制偏移量发送给主服务器。如果该复制偏移量仍然存在于复制积压缓冲区,则执行部分重同步操作,否则执行完整重同步操作。
服务器运行ID
每个Redis服务器都会有自己的运行ID,由40个随机的十六进制字符组成,在服务器启动时自动生成。当从服务器进行初次复制的时候,主服务器会将自己的运行ID传送给服务器。当从服务器断线重连时,从服务器发送之前保存的运行ID。如果主服务器接收到的运行ID与自己的运行ID相同,说明从服务器断线之前复制的就是当前连接的主服务器,则执行部分重同步操作,否则执行完整重同步操作。
命令传播
当同步操作完成以后,主从服务器的数据库达到一致的水平,但是每当主服务器执行客户端发送的写命令时,主服务器的数据库状态会被修改,导致主从服务器状态不一致。
为了让主从服务器保持一致的数据,主服务需要对从服务器执行命令保存操作,将主服务器的写指令发送给从服务器,当从服务器执行了该指令时,主从重新回到了一致的状态。
心跳检测
在命令传播阶段,从服务器会以每秒一次的频率向主服务器发送命令,告诉主服务器目前从服务器当前的复制偏移量。其作用有:
- 检测主从服务器之间的网络连接
- 辅助实现min-slaves选项
- 检测命令丢失
如果在心跳检测的过程中检测出命令丢失的情况,那么主服务器会根据从服务器提交的命令偏移量,在复制挤压缓冲区中找到从服务器中缺少的数据,并将这些数据重新发送给从服务器。
主从级联分担全量复制压力
在一次全量复制中,对于主库由两个耗时的操作:生成 RDB 文件和传输 RDB 文件。
如果从库数量很多,会导致出现主库忙于生成RDB文件,同时占用大量的网络资源用于传输RDB文件。可以通过“主 - 从 - 从”模式将主库生成 RDB 和传输 RDB 的压力,以级联的方式分散到从库上。
具体的方式为在部署主从集群的时候,可以选择通过手动选择一个从库用于级联其他从库。这些从库在进行同步时,不用再和主库进行交互了,只要和级联的从库进行写操作同步就行了,这就可以减轻主库上的压力。