复制
从服务器对主服务器进行复制,以达到数据库状态一致。
Redis2.8以前的复制功能:同步和命令传播。
同步
从服务器对主服务器的同步操作是通过向主服务器发送SYNC命令来完成的,步骤:
- 从服务器向主服务器发送SYNC命令;
- 收到SYNC命令的主服务器执行BGSAVE命令,在后台生成一个RDB文件,并使用一个缓冲区记录从此刻开始的所有写命令;
- 主服务器将RDB文件发送给从服务器,从服务器接收并载入这个RDB文件,将自己的数据库状态更新到主服务器执行BGSAVE时的数据库状态;
- 主服务器将记录在缓冲区的所有写命令发送给从服务器,从服务器执行这些写命令,将自己的数据库状态更新至主服务器数据库当前所处的状态。
命令传播
在同步后,主服务器会将自己执行的写命令,也即是造成主从服务器不一致的写命令,发送给从服务器执行以达到一致状态。
缺陷:若出现断线重新连接,从服务器会再次向主服务器发送SYNC请求重新同步一次,而不是执行从断线到重连这段时间内的写命令,这样会导致浪费。
Redis2.8开始,使用PSYNC命令代替SYNC命令来执行复制操作。PSYNC的两种模式:
- 完整重同步:与SYNC命令一样,主服务器创建并发送RDB文件,并向从服务器发送保存在缓冲区里的写命令来进行同步;
- 部分重同步:当从服务器断线后重新连接主服务器,如果条件允许,主服务器可将断开期间执行的写命令发送给从服务器以达到一致状态。
部分重同步的实现
- 复制偏移量
- 主服务器复制积压缓冲区
- 服务器运行ID
1、复制偏移量
执行复制的双方分别维护一个复制偏移量:
- 主服务器每次向从服务器传播N个字节的数据时,就将自己的复制偏移量的值加上N;
- 从服务器每次收到主服务器传播来的N个字节的数据时,就将自己的复制偏移量的值加上N。
通过对比主从服务器的偏移量是否相等可以判断是否处于一致状态。如果主从服务器不处于一致状态,那么需要执行完整重同步还是部分重同步取决于复制积压缓冲区。
2、复制积压缓冲区
复制积压缓冲区是由主服务器维护的一个固定长度的先进先出队列,默认大小为1MB。所谓固定长度的队列是指当元素个数超过指定队列长度时,若有新元素入队尾,则必先从队首弹出队首元素。
当主服务器进行命令传播时,不仅会将写命令发送给从服务器,还会将写命令写入复制积压缓冲区中。从服务器断线重连后,会通过PSYNC将自己的复制偏移量offset发送给主服务器,则
- 若offset之后的数据仍然在复制积压缓冲区中,则主服务器对从服务器执行部分重同步操作;
- 若offset之后的数据已不在复制积压缓冲区中,则主服务器(先发送+CONTINUE回复,再)对从服务器执行完整重同步操作。
3、服务器运行ID
主从服务器都有自己的运行ID,服务器启动时自动生成,由40个随机的十六进制字符组成。从服务器第一次对主服务器进行复制时,主服务器将自己的运行ID发给从服务器,从服务器将它保存起来;从服务器断线重连后,向主服务器发送该运行ID,若与当前主服务器ID相同,则执行部分重同步,否则执行完整重同步。
PSYNC命令实现原理
复制的实现
步骤:
- 从服务器根据客户端命令设置主服务器的IP地址和端口;
- 从服务器根据IP地址和端口建立连接主服务器的套接字,再为该套接字关联一个文件事件处理器用于处理复制工作;
- 从服务器向主服务器发送PING命令,用于
- 检查套接字读写状态是否正常;
-
检查主服务器能否正常处理命令请求。
-
身份验证:若从服务器设置了masterauth选项,那么进行身份验证,否则不验证;
从服务器向主服务器发送自己监听的端口号,主服务器保存该端口号;
同步;
命令传播。
心跳检测
在命令传播阶段,从服务器会每秒一次地向主服务器发送命令:
REPLCONF ACK <replication_offset>
该命令有三个作用:
- 检测主从服务器的网络连接状态;
- 辅助实现min-slaves选项(可防止主服务器在不安全的情况下执行写命令);
- 检测命令丢失:若主服务器命令传播丢失了,则REPLCONF ACK <replication_offset>可让主服务器发现与从服务器的偏移量不一致,引发部分重同步。