内容概述:
(1)旧版sync命令
(2)新版psync命令
(3)复制过程
在Redis中,用户可以通过执行slaveof或者设置slaveof选项,让一个服务器去复制另一个服务器。
主服务器:被复制的服务器
从服务器:进行复制的服务器
数据库状态一致:进行复制中的主从服务器双方的数据库将保存相同的数据
Redis 2.8版本之前的复制操作:
(1)同步操作:将从服务器的数据库状态更新到主服务器当前所处的数据库状态
(2)命令传播:当主服务器的数据库状态被修改,导致主从服务器的数据库状态不一致,让主从服务器的数据库重新回到一致状态。
【同步操作】
(1)从服务器向主服务器发送sync命令
(2)收到sync命令的主服务器执行BGSAVE命令,在后台生成一个RDB文件,并使用一个缓冲区记录从现在开始执行的所有写命令
(3)当主服务器的BGSAVE命令执行完后,主服务器将生成的RDB文件发送给从服务器,从服务器接受并载入这个RDB文件,将自己的数据库状态更新至RDB文件的状态
(4)主服务器将记录在缓冲区里面的所有写命令发送给从服务器,从服务器执行,更新状态。
【命令传播】
当主服务器执行客户端发送的写命令时,主服务器的数据库可能被修改,导致状态不一致。
为了一致,需要对主服务器对从服务器执行命令传播操作:
主服务器会将自己执行的写命令,发送给从服务器执行,当从服务器执行了相同的写命令之后,主从服务器再次回到一致状态。
【旧版缺陷】
断线后重复制:处于命令传播阶段的主从服务器因为网络原因中断了复制,但从服务器通过自动重连接连接上了主服务器,并继续复制主服务器
在复制时断线后,从服务器会再次发送sync命令,此时主服务器会将重新生成RDB文件,发送给从服务器,更新状态,但是把发送RDB整个文件是不必要的,因为RDB文件中的数据可能大部分已经更新完。
SYNC命令是一个消耗资源的命令:
(1) 主服务器需要执行BGSAVE命令来生成RDB文件,这个操作会消耗主服务器大量的CPU,内存 和 磁盘 I/O 资源
(2) 主服务器需要将生成的RDB文件发送给从服务器,这个发送操作会消耗主从服务器大量网络资源(带宽和流量),并对主服务器想要命令的请求产生影响
(3) 载入RDB文件时,从服务器会因为阻塞而不能处理命令请求
Redis2.8之后的复制操作
使用psync代替sync执行复制操作
psync命令具有完整重同步和部分重同步 两种模式
完整重同步:用于处理初次复制情况,同sync命令
部分重同步:用于处理断线后重复制的情况
出现断线重复制时,主服务器可以将主从服务器连接断开期间执行的写命令发送给从服务器,从服务器执行这些写命令,更新状态。
【部分重同步的实现】
复制偏移量,复制积压缓冲区,服务器的运行ID
【复制偏移量】
主从服务器会分别维护一个复制偏移量:
主服务器每次传播N个字节的数据时,将自己的复制偏移量加上N
从服务器每次接受N个字节的数据时,将自己的复制偏移量加上N
通过对比主从服务器的复制偏移量,可以很容易的知道主从服务器是否处于一致状态:
偏移量相同,主从服务器处于一致状态,否则处于不一致状态
偏移量不相同,从服务器会将自己的偏移量offset发送给主服务器,主服务器会根据这个偏移量决定对从服务器执行何种同步操作。
(1)如果offset偏移量后的数据仍然存在在复制积压缓冲区里面,那么主服务器将发送+CONTINUE命令回复,对从服务器执行部分重同步操作
(2)否则执行完整重同步操作
【复制积压缓冲区】
复制积压缓冲区是由主服务器维护的一个固定长度的先进先出的队列,默认大小为1MB。
当主服务器进行命令传播时,不仅会将写命令发送给所有从服务器,还会将写命令入队到复制积压缓冲区里面。
因此,主服务器的复制积压缓冲区会保存着一部分最近传播的写命令,并且复制积压缓冲区会为队列中的每个字节记录相应的复制偏移量。
【服务器运行ID】
每个Redis服务器都有自己运行ID,在服务器启动时自动生成,由40个随机的十六进制字符组成。
当从服务器对主服务器初次复制时,主服务会将自己的ID传送给从服务器,从服务器会将这个ID保存起来。
当从服务器断线并重新连接上一个主服务器时,从服务器将保存的ID发送给当前连接的主服务器
(1)如果两个ID相同,说明断线之前复制的就是当前连接的主服务器,主服务器执行部分重同步操作
(2)否则,说明断线之前复制的不是当前连接的主服务器,主服务器执行完整重同步操作
【复制的实现】
1.【设置主服务器的地址和端口】
当客户端向从服务器发送
从服务器将给定的主服务器IP地址和端口保存到服务器状态的masterhost属性和masterport属性里面。
随后,从服务器发送slaveof命令的客户端返回OK,表示复制指令已经被接受,之后执行复制操作
2.【建立套接字连接】
从服务器根据命令的IP地址和端口,创建连向主服务器的套接字连接。
如果从服务器创建的套接字能成功连接到主服务器
从服务器会为这个套接字关联一个专门用于处理复制工作的文件事件处理器,这个处理器将负责执行后续的复制工作,如果接受RDB文件,接受主服务器传播来的写命令。
主服务器会为该套接字创建相应的客户端状态,并将该服务器看做是一个连接到主服务器的客户端来对待。这时从服务器将同时具有服务器和客户端两个身份:从服务器可以向主服务器发送命令请求,主服务器会回复命令。
3.【发送PING命令】
从服务器成为主服务器的客户端之后,向主服务器发送一个PING命令。
(1)使用PING命令检查套接字的读写状态是否正常
(2)使用PING命令检查主服务器能否正常处理命令请求
4.【身份验证】
如果从服务器设置了masterauth,或这主服务器设置requirepass选项,需要进行身份验证。
5.【发送端口信息】
从服务器执行命令replconf listening-port <port-number>,向主服务器发送从服务器的监听端口号。
主服务器在接受到这个命令之后,会将端口号记录在从服务器所对应的客户端状态slave_listening_port属性中。
slave_listening_port属性唯一作用就是在主服务器执行INFO replication打印出从服务器的端口号。
6.【同步】
从服务器向主服务器发送psync命令,执行同步操作,更新状态。
在执行同步操作后,主服务器也会成为从服务器的客户端。
主服务器需要保存在缓存区或积压缓冲区的写命令发送给从服务器执行,所以主服务器必须要成为从服务器的客户端。
因此在同步操作执行之后,主从服务器双方都是对方的客户端,可以互相向对方发送命令请求或回复命令。
7.【命令传播】
当完成 了同步操作之后,主服务器只要一直将自己执行的写命令发送给从服务器,而从服务器只要一直接受并执行主服务器发送来的写命令,就可以保证主从服务器一致。
【心跳检测】
在命令创博阶段,从服务器默认会以每秒一次的频率,向主服务器发送命令:
(1)检测主从服务器连接状态
(2)辅助实现min-slaves配置选项
redis的min-slaves-to-write(最少从服务器个数) 和min-slaves-max-lag(最大延迟) 两个选项可以防止主服务器在不安全的情况下执行写命令。
(3)检测命令丢失:比较偏移量