Redis设计与实现之复制

Redis中用户通过执行slaveof命令或者设置slaveof选项,让一个服务器去复制另一个服务器。被复制的称为主服务器(master),复制的称为从服务器(slave)。

1,旧版复制功能及其缺点

redis的复制功能,分为同步和命令传播两个操作:
同步:将从服务器的状态更新至主服务器目前所处的状态
命令传播:主服务器对数据库状态进行修改导致主从服务器状态不一致时,让主从服务器数据库恢复至统一状态。

1,1同步

当客户端向服务器发送slaveof命令,要求从服务器复制主服务器时,从服务器要先执行同步操作。
同步操作是从服务器向主服务器发送sync命令完成,执行步骤:
1)从服务器向主服务器发送sync命令
2)收到sync的主服务器开始执行bgsave,在后台生成一个RDB文件,并使用一个缓冲区记录当前开始服务器执行的所有写命令
3)bgsave执行完毕之后,主服务器将bgsave命令生成的RDB文件发送给从服务器。从服务器使用RDB文件,更新数据库到执行bgsave时的状态
4)主服务器将记录在缓冲区中的所有写命令发送给从服务器,从服务器执行这些命令,将数据库更新到主服务器当前的状态

1,2命令传播

同步操作完成之后,主从服务器达到的数据库一致状态并不是一成不变的。当主服务器再执行写命令,就会再次导致主从不一致这个时候需要使用命令传播操作:主服务器将导致主从不一致的写命令发送给从服务器执行,再次达到主从一致状态。

1,3旧版复制功能缺点

Redis中的复制有初次复制和断线后重复制两种。对于初次复制,旧版复制功能可以很好的完成。但是对于断线后复制,旧版复制功能会效率比较低,原因是断线后重复制只需要执行断线期间执行的写命令并不需要重新生成RDB文件,但是旧版复制功能会再次使主服务器执行非常耗费资源的bgsave从而导致效率低下。

2,新版复制功能

新版复制功能解决了旧版复制处理断线重复制遇到的问题,使用psync代替sync命令,将复制分为完整重同步和部分重同步两个模式:
完整重同步:适用于初次复制的情况与sync的执行过程一样。
部分重同步:适用于断线重复制的情况,从服务器断线后重新连接主服务器,并请求同步。主服务器根据情况将断开期间执行的写命令发给从服务器,而不必重新生成RDB文件。
部分重同步功能的实现由三个部分构成:
1,主从服务器各自维护的复制偏移量
2,主服务器的复制积压缓冲区
3,服务器的运行ID
复制偏移量:主从服务器各自维护的复制偏移量表示当前复制了多少字节数据。主服务器想从服务器传播N个字节数据时,就将自己的复制偏移量加N。从服务器每次从主服务器接受N字节的数据,也将自己的复制偏移量加N。主从双方通过复制偏移量判断状态是否一致。
复制积压缓冲区:由主服务器维护的一个固定长度的先进先出队列,默认大小1MB。因为是固定大小,所以当缓冲区满的时候旧元素就会被弹出给新元素留出空间。主服务器运行期间复制积压缓冲区会根据每秒产生的命令数和服务器断线重连的时间间隔进行调整。不小于2*second*write_size_per_second
当主服务器进行命令传播的时候,不仅会将写命令发送给所有的从服务器,也会写入复制积压缓冲区中。因此复制积压缓冲区中保存了一部分最近传播的写命令,并且复制积压缓冲区也会为队列中的每一个字节记录相应的复制偏移量。当从服务器再次连上主服务器时,发送psync命令将自己的offset发给主服务器,主服务根据offset来决定对其执行哪种同步操作:
1)如果offset偏移量后的数据还在复制积压缓冲区中,就执行部分重同步操作,将需要的命令发送给从服务器执行
2)如果offset偏移量后的数据不在复制积压缓冲区中,就执行完整重同步操作。
服务器运行ID:每个Redis服务器(所有)都会在启动的时候自动生成一个40个随机的16进制字符的运行ID。
从服务器进行初次复制的时候,主服务器会将自己的ID发送给从服务器,从服务器会保存主服务器ID。当从服务器断线并重新连接到一个主服务器时,从服务器会将之前保存的ID发送给当前的主服务器:
1)如果从服务器发送的ID和当前主服务器ID相同,可以尝试部分重同步
2)两个ID不同,说明之前链接的不是同一个服务器,要执行完整重同步
psync的执行过程如下:
Redis设计与实现之复制_第1张图片

3,复制功能的实现

使用slaveof 命令,我们让一个从服务器去复制主服务器,详细步骤如下:

3.1,设置主服务器ip和port

从服务器收到命令之后,会在redisServer的masterhost和masterport属性中设置master的ip和port,然后向发送slaveof命令的客户端返回ok,表示复制命令已接收,但现在真正的复制工作才开始。

3.2,建立套接字

从服务器向主服务器建立套接字用于命令请求与命令回复如RDB文件接收等。此时,从服务器是主服务器的客户端。

3.3,发送ping命令

套接字建立之后,从服务器向主服务器发送一个ping命令,主要用于检查套接字的读写状态是否正常以及主服务器能否正常处理命令请求。
if 主服务器返回pong
表示一切正常,继续执行下一个步骤
else if 读取ping命令超时 or 主服务器返回错误
断开重连主服务器

3.4,身份验证

如果从服务器设置了masterauth选项就进行身份验证,否则不验证。如果验证就向主服务器发送auth命令,参数为masterauth选项中获得的值。
Redis设计与实现之复制_第2张图片

3.5,发送端口信息

从服务器执行replconf listening-port ,向主服务器发送从服务器的监听端口号。主服务器会将其记录在redisClint相应字段中。

3.6,执行同步

从服务器向主服务器发送psync命令,执行同步操作,将自己的数据更新至主服务器相同的状态。因为同步过程中及之后,双方都要向对方发送命令所以主从服务器之间互为客户端。

3.7,命令传播

完成同步之后,主从服务器就进入了命令传播阶段,此时主服务器一直将自己执行的写命令发送给从服务器执行,双方就可以保持一致状态。

3.4,心跳检测

命令传播阶段,从服务器每秒一次向主服务器发送命令:replconf ack #复制偏移量,然后等待回应。
作用有三个:
1,检测主从之间的网络连接状态
2,辅助实现min-slaves选项,为防止主服务器在不安全的情况下执行写命令,当从服务器数量少于min-slaves-to-write所指定的或者服务器的延迟都大于或等于min-slaves-max-lag时,主服务器将拒绝执行写命令。
3,检测写命令丢失,通过验证offset是否一致,保证双方的状态一致。

你可能感兴趣的:(数据库)