0 摘要
主从同步机制三个阶段:
- 第一次复制通过全量复制,全量复制完成之后(psync + RDB文件+repl_buffer);
- 命令传播阶段(通过长连接+repl_buffer保证 命令顺序性+ repl_backlog_buffer 实现数据补发);
- 恢复断连阶段增量同步(psync +repl_backlog_buffer )。redis 2.8之前和全量同步类似,通过psync代替sync实现增量同步。
命令传播阶段是否会出现:第一指令没有成功,第二个成功了?
不会。
1 全量复制和增量复制
1.1 全量复制
从节点与主节点第一次建联成功后执行全量同步流程如下:
- slave节点向master节点发送“psync ? -1” 命令;
- master收到psync命令之后返回 FULLRESYNC 告知 slave 将执行全量同步;
- master执行bgsave命令,Redis会fork出一个子进程在后台生成RDB文件,同时将同步过程中的写命令记录到replication_buffer中;
- master会把生成的RDB文件发送给slave;
- slave接收到RDB文件会将其装载入内存;
- master将记录在复制缓冲区replication_buffer的所有写命令发送给slave,slave对这些命令进行「重放」,将其数据库的状态更新至和master一致。
如下图
1.2 断连处理-增量复制
在Redis 2.8之前,如果因网络原因,主从节点复制中断,当再次建立连接时,还是会执行SYNC命令进行全量复制。效率较为低下。从Redis 2.8开始,引入了PSYNC命令代替SYNC命令来执行复制时的同步操作。PSYNC命令相比之前SYNC提供了增量复制。
注意: “PSYNC ? -1 ” 和SYNC作用相同,都是全量复制。
PSYNC通过复制挤压缓冲区repl_backlog_buffer实现增量复制,流程如下:
- 断连期间,主库将命令记录到repl_backlog_buffer,并更新master_repl_offset;
- 断连恢复,
1)从库通过PSYNC ,发送salve_repl_offset 到主库
2)主库将salve_repl_offset和master_repl_offset之间的数据发送给从库,即断连之间的数据
注意:repl_backlog_buffer是环形缓存区,如果断连时间过长,主从不同步的命令超过缓冲区大小,此时会进行全量同步。
2 基于长连接的命令传播
解释下repl_backlog_buffer和replation_buffer两个缓存的区别?
replation_buffer每个长连接独享一个,建立主从连接之后生成的:
a:全量复制过程中,解决RDB生成、传输和加载过程中增量写问题;
b:命令传播过程中,实现命令按顺序同步到从节点。
relation_backlog_buffer所有长连接共享一个,redis服务初始化时候生成的:
a:恢复断连过程中实现增量复制;
b:命令传播过程中实现数据补发。
在命令传播阶段,一个写命令到master之后会更新两个buffer:
a:repl_backlog_buffer追加写命令;
b:replation_buffer追加写命令。
注意:redis7之后将上述两个缓冲区合并了,简称 共享复制缓冲区 ,具体可以查询相关文档
当主从库完成了全量复制,它们之间就会一直维护一个长连接,主库会通过这个长连接将后续陆续收到的写操作命令(replation_buffer中命令)发送给对应的从库,这个过程也称为基于长连接的命令传播,使用长连接的目的就是避免频繁建立连接导致的开销。
2.1 命令传播如何保证顺序性和完整性
假设,当前主从节点的repl_offset为1000,如下两个命令顺序达到主库:
- 命令1 -> 保存到缓存repl_backlog_buffer (200个字节)&&更新master_repl_offset 1200 -> 异步发送命令给从节点offset。
- 命令2 -> 保存到缓存repl_backlog_buffer(300个字节)&&更新offset 1500 -> 异步发送命令给从节点。
Q: 在将命令1和命令2同步到从库过程中是否出出现: 命令1丢失(失败)了,命令2正常写入从节点,即此时从节点offset为1300,然后从节点执行 REPLCONF ACK 1300,主从节点各如何处理?
A: 不会出现这个问题。分两种情况讨论:
1)master保证命令按序同步给slave,因为主节点往从节点发送命令是通过replation_buffer进行的,replation_buffer是每个从节点长连接独享一个,所以保证了master同步到slave的命令的有序性,如上面命令传播流程图。
2)slave收到命令后执行失败,这种情况下slave会主动断开长连接,然后重连会进行增量复制,保证命令不丢失。
2.2 心跳检测REPLCONF_ACK
在命令传播阶段,从节点间隔1秒向服务器发送一个“REPLCONF ACK{offset}” 命令。命令作用为:
- slave上报资损复制偏移量,检查是否存命令丢失。主节点判断master_repl_offset和slave_repl_offset是否一致性,不一致性就行数据补发操作;
- 判断master是否在线,如果超时则认为为master下线,1)将传播命令的长连接关闭;2)等下次进行心跳检查,如果连接上,则触发增量同步PSYNC
- master确定从节点数量和每个从节点同步延迟时间,通过min-slaves-to-write、 minslaves-max-lag参数配置定义。
数据补发和增量复制区别:
- 增量复制是主从连接断连,在连接恢复之后,从节点发送PSYNC 进行触发的;
- 数据补发是在主从连接没有断连的情况下执行的。通过REPLCONF ACK{offset}触发。
3 拓扑结构- 主-从-从
为了降级master同步的压力,多采用“主-从-从”的复制模式。