昨天把集群装了一下,也是因为往下的学习都是基于多机的基础。当然集群是集群,多机是多机。
复制这一节介绍了老版本的复制和缺陷,以及新版本的复制。
旧版复制功能
Redis的复制功能分成同步(sync)和命令传播(commond propagate)
同步
当出现SLAVEOF命令时,要求从服务器复制主服务器时,从服务器首先需要执行同步操作,将从服务器的数据库状态更新至主服务器当前所处的数据库状态。
从服务器需要通过向主服务器发送SYNC命令来完成
执行步骤:
1.从服务器向主服务器发送SYNC命令
2.收到SYNC的主服务器执行BGSAVE命令,在后台生成一个RDB文件,并使用缓冲区记录从现在开始执行的命令操作。
3.当主服务器的BGSAVE命令执行完毕,主服务器会将BGSAVE命令生成的RDB文件发送给从服务器,从服务器接收并执行这个RDB文件,将自己数据库状态更新至主服务器并执行BGSAVE命令时的数据库状态
4.主服务器将记录在缓冲区里面所有的写命令发送个从服务器,从服务器执行这些写命令,将自己的数据库状态更新至主服务器数据库当前所处的状态。
命令传播
当同步操作执行完毕时,主从服务器状态一致,但是当主服务器执行命令时,主从的状态可能被打破。
这个时候主服务器就需要把DEL k3命令发送给从服务器,让它删除,从而保证主从状态一致。
旧版复制的缺陷
说道缺陷,就需要说下复制的情况:
初次复制:从服务器上数据库状态和上一次复制的主服务器不同,或者第一次复制
断线后复制:处于命令传播阶段时,主从丢失链接中断了复制,但是从服务器通过自动链接重新链接上,并继续复制。
问题其实一眼就能看见,就是在T10092时刻,当从服务器经过断线重连之后,又发送了一个SYNC命令,从而使得主服务器又执行了一次RDB文件的生成,上例子中只有k10087-k10089三个命令,但是确重新执行了一次RDB的生成操作,低效。
新版复制功能
新版复制是指从2.8开始就是为了处理断线重连时的复制低效问题。
PSYNC代替SYMC:具有完整同步和部分重同步
完整重同步
和旧版本的SYNC一样,都是主服务器生成RDB,然后从服务器接收更新。
部分重同步
当从服务器断线后重新连接上主服务器时,如果条件允许,主服务器可以将主从断开期间执行的写命令发送给从服务器,从服务器可以只更新这些命令,达到一致状态。
部分重同步的实现细节
由上图可见,部分重同步只在断线重连接成功后执行了断线期间的命令,PSYNC命令类似三次握手,通知,接收结果,做准备,执行命令同步。
主要三部分:
1.主服务的复制偏移量和从服务器的复制偏移量
2.主服务的复制积压缓冲区
3.服务器的运行ID
复制偏移量
其实不看下面的分析就已经知道这个偏移量是用来干嘛的了,保证两边同时偏移相同的量,这样才能保证数据库状态一致。
1.主服务器每次向从服务器传播N个字节,将自己的偏移量增加N。
2.从服务器每次收到主服务器传播来的N字节,将自己的复制偏移量增加N
复制积压缓冲区
但是上面都是正常情况,没有断线,正常偏移,一旦出现断线重连的话,怎么处理的。下面就是这个场景。从服务器A断线了重连了,那么主服务器是怎么执行呢?是执行完整重同步还是执行部分重同步呢?
这边写说下缓冲区的构造,缓冲区是一个先进先出队列。默认大小是1MB。
当主服务器进行命令传播时。不仅会将命令传递给从服务器,并且还会将写命令入队到复制积压缓冲区里面。如下图:
那么复制积压缓冲区里面会保存着一部分最近传播的写命令,并且复制积压缓冲区会为队列中的每个字节记录相应的复制偏移量,like下图:
有这个记录就好办多了,既然在断线之后的所有操作都有一个缓冲区存储,那就有一个参照了。
1.如果offset偏移量之后的数据仍然存在于复制积压缓冲区里面,那么主服务将对从服务执行部分重同步。
2.如果offset偏移量之后的数据已经不存在复制积压缓冲区了,联系到缓冲区是一个FIFO队列,那么就意味着超出了存储范围,那么会执行完整重同步操作。
回到图15-9中的场景中
1.从服务器A断线重连了,然后发送PSYNC命令,告诉主服务器我现在的偏移量是10086.
2.主服务器收到命令之后检查10086是否在积压缓冲区里面,发现在的,就回复+CONTINUE,这就是一开始的那个类似三次握手那儿,告诉从服务器我收到命令了,准备执行部分重同步,你做好准备。
3.接着主服务器将复制缓冲区10086偏移量之后的所有数据发送给从服务器。
4.从服务器更新自己的服务器状态,保持一致。
复制积压缓冲区的大小设置依据:
运行ID
运行ID是关键的一个点,因为正式环境内,主服务器不一定就是唯一固定的。
当从服务器对主服务器进行初次复制时,会记录下主服务器的运行ID,当断线重连时:
1.如果ID还是一致的,说明可以尝试部分重同步操作。
2.如果ID不一致,那就肯定不能执行部分重同步,需要执行完整重同步。
PSYNC实现
主要是看从服务器发送的命令和主服务器回复的命令可以看出执行哪种同步方式。
复制的实现
设置服务器地址和端口。
这操作是异步的,客户端里面会返回OK,但是真正的复制工作在OK返回之后才真正执行
建立套接字
此时从服务器会向主服务器创建套接字连接。
1.如果成功了,从服务器会为这个套接字创建一个专门用于处理复制工作的文件事件,关于事件,我没有去看,处理后续的复制工作,比如RDB的接收,接收主服务器传播的写命令。
2.而此时主服务器会为这个套接字创建相应的客户端状态,并将从服务器当做一个客户端对待,这时,从服务器具有服务器和客户端两个身份
发送PING命令
当套接字建立起来之后,也就是从服务器成为主服务器的客户端之后,紧接着就是ping命令,测试连接是否正常。
PING的作用有两个:
1.检查套接字的读写状态是否正常
2.检查主服务器能否正常处理命令请求。
主服务器的返回:
1.主服务器成功返回,但是从服务器不能在timeout期间接收返回值,表示主从间服务不稳定,不能执行后续操作。从服务器需要断开并重新创建套接字。
2.主服务器返回一个错误,表示主服务器不能进行复制工作,从服务器需要断开并重新创建套接字,最明显的是主服务器正在执行一个超时任务。
3.返回PONG命令,表示网络正常,并且主服务器可以正常处理命令请求。
身份验证
身份验证是发生在设置了 masterauth参数的情况下,不过我本机没有设置验证,主要围绕了masterauth和requirepass两个参数进行。
1.主服务器没有设置requirepass,并且从服务器也没有设置masterauth,可以进行复制工作。
2.从服务器设置了masterauth,但是和主服务器的requirepass不一致,那么会出现invalid password
3.主服务器设置了requirepass,但是从服务器确没有设置masterauth,那么主服务器会返回NOAUTH。另一面,主服务器没有设置requirepass,但是从服务器设置了masterauth,那么主服务器返回no password is set。
发送端口信息
身份验证通过后,从服务器会发送自己的端口信息给主服务器
主服务器会记录在自己的客户端信息中
同步
此时,从服务器才真正发送PSYNC命令
命令传播
完成同步之后,主服务器只要一直将自己的执行的写命令发送给从服务器,从服务器不断接收,执行就行。
心跳检测机制
REPLCONF ACK <replication_offset>
replication_offset 是从服务器当前的偏移量。
只要作用有三:
1.检测主从服务的网络连接状态
2.辅助实现min-slaves选项
3.检测命令丢失。
检测主从服务的网络连接状态
lag小于1S是正常的
辅助实现min-slaves选项
两个配置项:
min-slaves-to-write
min-slaves-max-lag
提供以下配置项:
min-slaves-to-write 3
min-slaves-max-lag 10
在从服务器的数量小于3个,或者三个从服务器的延迟(lag)值都大于10S时,主服务器拒绝执行写命令检测丢失
丢失的情况发生在本来主从状态一致,但是主服务器进行了写命令,在传输给从服务器时发生了丢失,导致了主从不一致,此时如果从服务器发送心跳命令,主服务器会察觉到从服务器的偏移量依然在200,而本身自己的偏移量子啊233,说明积压缓冲区里面201-233的数据丢失了,于是主服务器会再次向从服务器传播命令,