为了提供整个缓存的可用性,可以给主服务器添加备用服务器,即从服务器。通过SLAVEOF命令把当前服务器设置成某台服务器的从服务器。
老版本同步过程
旧版本(2.8之前)主从服务器数据同步过程如下:
- 从服务器向主服务器发送SYNC命令。
- 主服务器接收到SYNC命令后调用BGSAVE命令生成一个RDB文件,在此过程中客户端对主服务器的修改命令存放在一个缓冲区中。
- 主服务器把生成的RDB文件发送给从服务器,从服务器通过加载该RDB文件更新数据库状态。
- 主服务器把缓冲区中的命令同步到从服务器,从服务器执行这些命令更新数据库。
老版本在SYNC命令同步处理有非常大的性能缺陷,在主从服务器断线重连之后执行同步动作时,也会生成完整的RDB文件并且发送到从服务器载入,但是主从服务器的数据库状态在断线前基本上是一致的,不一致的部分只有断线后主服务器执行那一部分修改数据库的命令,所以这时候SYNC命令就显得非常浪费,因为生成RDB文件时一个非常消耗CPU、内存和IO资源的过程,而发送RDB文件到从服务器也会占用大量的网络带宽资源,从服务器在载入RDB文件的过程中也阻塞不会相应任何命令,所以大部分情况下执行SYNC命令是没有必要也是非常不合理的。
为了解决2.8之前版本SYNC命令的性能问题,2.8版本设计了一个新的命令PSYNC,PSYNC命令分为完整重同步和部分重同步,完整重同步过程用于从服务器初始化时初次复制的情况和SYNC命令基本一致,PSYNC则用于断线后重新复制,在条件允许的情况下,它不会生成RDB文件,而是给从服务器回复一个+Continue表示执行部分重同步,并且把从服务器断线后主服务器执行的修改数据库的命令发送到从服务器,从服务器执行这些命令同步数据库。
部分重同步功能由下面几个部分构成:
- 主服务器的复制偏移量和从服务器的复制偏移量:当主服务器在向从服务器进行命令同步时,主服务器和从服务器会各自记录一个复制偏移量,当主从服务器的数据库状态一致时这两个复制偏移量是相同的,如果这两个偏移量不一致说明当前主从服务器的状态不一致。
- 主服务器的复制积压缓冲区:复制积压缓冲区是一个固定大小的FIFO队列,当队列已满时会弹出最早插入的数据,在主服务器进行命令传播时会同时把命令放到缓冲区中,缓冲区包含两部分数据,偏移量和字节。在进行复制时从服务器会将偏移量上报到主服务器,主服务检查当前偏移量是否还存在缓冲区中,如果存在进行部分重同步,如果不存在进行完整重同步。因为这个积压缓冲区是一个固定大小的队列,所以当从服务器长时间断线时,从服务器的复制偏移量很可能已不再缓冲区中,这时候只能进行完整重同步。
- 服务器的运行ID:初次同步时主服务器会把ID发给从服务器,从服务器保存主服务器ID,当断线重连后,会把之前保存的主服务器ID上报给主服务器,主服务器检查从服务器之前复制的主服务器ID是否和自己的ID相同,如果相同,执行部分重同步,如果不同说明从服务器之前记录的状态不是当前主服务器,这时候需要执行完整重同步。
PSYNC命令实现
初始复制或者之前执行过SLAVEOF no one命令,执行完整重同步:发送PSYNC ? -1命令到主服务器。
如果从服务器已经复制过某个主服务器,在开始新复制时向主服务器发送PSYNC <runid> <offset>命令,runid是上次复制的主服务器id,offset是从服务器的复制偏移量,主服务器会根据这个两个参数来决定做哪种同步,判断服务器id是否和本机相同,复制偏移量是否在缓冲区中,主服务器有三种回复:
- 回复+FULLRESYNC <runid> <offset>执行完整重同步,从服务器把offset当做初始复制偏移量
- 回复+CONTINUE,表示执行部分重同步,从服务器等待主服务器发送缺少的数据
- 回复-ERR,表示主服务器版本低于2.8,不支持PSYNC命令
新版本同步过程
2.8及以后版本复制过程:
- 设置主服务器地址和端口,通过调用SAVEOF <master_ip> <master_port>命令。
- 建立套接字连接。
- 发送PING命令,检查主从服务器是否能够正常处理命令。
- 身份验证,从服务器设置了masterauth并且主服务器设置了requirepass是需要进行身份验证。这两个选项要么都设置要么都不设置,如果只设置了一个从服务器向主服务器发送命令时会报错。
- 发送端口信息,通过执行命令REPLCONF listening-port <port-number>,向主服务器发送从服务器的监听端口号。
- 同步,从服务器向主服务器发送PSYNC命令。
- 命令传播,完成同步之后主服务器会把之后执行的写命令传播到从服务器保证主从服务器的状态一致。
心跳检测
在命令传播阶段,从服务器默认每秒一次的频率向主服务器发送命令:REPLCONF ACK <replication_offset>,replication_offset是从服务器的复制偏移量,该命令有三个作用:
- 检测从服务器的网络连接状态,检测主从服务器连接是否正常,如果主服务器超过一定时间没有收到从服务器的REPLCONF ACK 命令,那么它们的连接可能出了问题。
- 辅助实现min-slaves选项,min-slaves-to-write和min-slaves-max-lag两个选项可以防止主服务器在不安全的情况下执行写命令,min-slaves-to-write 3 min-slaves-max-lag 10 表示如果从服务器少于3个,或者3个从服务器的延迟都大于10秒时,主服务器拒绝写命令。
- 检测命令丢失,主服务器接收到从服务器的REPLCONF ACK 命令之后会检查从服务器的偏移量是否和主服务器的一致,如果不一致会把积压缓冲区中的从服务器偏移量后面的命令发送到从服务器。