redis全量复制


全量复制是Redis最早支持的复制方式, 也是主从第一次建立复制时必须经历的阶段。 触发全量复制的命令是sync和psync, 它们的对应版本如图:Redis版本复制命令差异
 



Redis 全量复制详解_运维


 


流程说明:
1) 发送psync命令进行数据同步, 由于是第一次进行复制, 从节点没有复制偏移量和主节点的运行ID, 所以发送psync -1。
2) 主节点根据psync -1解析出当前为全量复制, 回复+FULLRESYNC响应。
3) 从节点接收主节点的响应数据保存运行ID和偏移量offset, 执行到当前步骤时从节点打印如下日志:

1734:S 11 May 2020 11:46:39.597 * Full resync from master: c99ea11437b9df513dc5b29cc449de14fd7813bc:0

自己测试
1734:S 11 May 2020 11:46:39.597 * Full resync from master: c99ea11437b9df513dc5b29cc449de14fd7813bc:0

4) 主节点执行bgsave保存RDB文件到本地,主节点bgsave相关日志如下:

M * Full resync requested by slave 127.0.0.1:6380
M * Starting BGSAVE for SYNC with target: disk
C * Background saving started by pid 32618
C * RDB: 0 MB of memory used by copy-on-write
M * Background saving terminated with success


自己测试如下:
10835:M 11 May 2020 11:46:39.789 * Starting BGSAVE for SYNC with target: disk
10835:M 11 May 2020 11:46:39.789 * Background saving started by pid 10840
10840:C 11 May 2020 11:46:39.797 * DB saved on disk
10840:C 11 May 2020 11:46:39.797 * RDB: 4 MB of memory used by copy-on-write
10835:M 11 May 2020 11:46:39.865 * Background saving terminated with success
10835:M 11 May 2020 11:46:39.866 * Synchronization with replica 192.168.179.104:6379 succeeded

 5) 主节点发送RDB文件给从节点, 从节点把接收的RDB文件保存在本地并直接作为从节点的数据文件, 接收完RDB后从节点打印相关日志, 可以在日志中查看主节点发送的数据量:

16:24:03.057 * MASTER <-> SLAVE sync: receiving 24777842 bytes from master

自己测试
1734:S 11 May 2020 11:46:39.664 * MASTER <-> REPLICA sync: receiving 175 bytes from master

需要注意, 对于数据量较大的主节点, 比如生成的RDB文件超过6GB以上时要格外小心。 传输文件这一步操作非常耗时, 速度取决于主从节点之间网络带宽, 通过细致分析Full resync和MASTER<->SLAVE这两行日志的时间差, 可以算出RDB文件从创建到传输完毕消耗的总时间。

1734:S 11 May 2020 11:46:39.597 * Full resync from master: c99ea11437b9df513dc5b29cc449de14fd7813bc:0
1734:S 11 May 2020 11:46:39.597 * Discarding previously cached master state.
1734:S 11 May 2020 11:46:39.664 * MASTER <-> REPLICA sync: receiving 175 bytes from master

Full resync from master----------->MASTER <-> REPLICA sync: receiving 175 bytes from master
之间时间间隔可以算出RDB消耗的时间

如果总时间超过repl-timeout所配置的值(默认60秒) , 从节点将放弃接受RDB文件并清理已经下载的临时文件, 导致全量复制失败, 此时从节点打印如下日志:

M 27 May 12:13:33.669 # Client id=2 addr=127.0.0.1:24555 age=1 idle=1 flags=S
qbuf=0 qbuf-free=0 obl=18824 oll=21382 omem=268442640 events=r cmd=psync
scheduled to be closed ASAP for overcoming of output buffer limits.

repl-timeout:slave和master之间的复制超时时间,默认为60s, 推荐设置为180s;
a) slave角度,如果在repl-timeout时间内没有收到master SYNC传输的rdb snapshot数据,
b) slave角度,在repl-timeout没有收到master发送的数据包或者ping。
c) master角度,在repl-timeout时间没有收到REPCONF ACK确认信息。
当redis检测到repl-timeout超时(默认值60s),将会关闭主从之间的连接,redis slave发起重新建立主从连接的请求。
对于内存数据集比较大的系统,可以增大repl-timeout参数。
 

6) 对于从节点开始接收RDB快照到接收完成期间, 主节点仍然响应读写命令, 因此主节点会把这期间写命令数据保存在复制客户端缓冲区内, 当从节点加载完RDB文件后, 主节点再把缓冲区内的数据发送给从节点, 保证主从之间数据一致性。 如果主节点创建和传输RDB的时间过长, 对于高流量写入场景非常容易造成主节点复制客户端缓冲区溢出。 默认配置为clientoutput-buffer-limit slave 256MB 64MB 60, 如果60秒内缓冲区消耗持续大于64MB或者直接超过256MB时, 主节点将直接关闭复制客户端连接, 造成全量同步失败。 对应日志如下:

M 27 May 12:13:33.669 # Client id=2 addr=127.0.0.1:24555 age=1 idle=1 flags=S
qbuf=0 qbuf-free=0 obl=18824 oll=21382 omem=268442640 events=r cmd=psync
scheduled to be closed ASAP for overcoming of output buffer limits.

因此, 运维人员需要根据主节点数据量和写命令并发量调整clientoutput-buffer-limit slave配置, 避免全量复制期间客户端缓冲区溢出。
对于主节点, 当发送完所有的数据后就认为全量复制完成, 打印成功日志: Synchronization with slave127.0.0.1: 6380 succeeded, 但是对于从节点全量复制依然没有完成, 还有后续步骤需要处理。

7) 从节点接收完主节点传送来的全部数据后会清空自身旧数据, 该步骤对应如下日志:

16:24:02.234 * MASTER <-> SLAVE sync: Flushing old data

自己测试
1734:S 11 May 2020 16:54:42.833 * MASTER <-> REPLICA sync: Flushing old data

8) 从节点清空数据后开始加载RDB文件, 对于较大的RDB文件, 这一步操作依然比较耗时, 可以通过计算日志之间的时间差来判断加载RDB的总耗时, 对应如下日志: 

16:24:03.578 * MASTER <-> SLAVE sync: Loading DB in memory
16:24:06.756 * MASTER <-> SLAVE sync: Finished with success

自己测试
1734:S 11 May 2020 16:54:42.833 * MASTER <-> REPLICA sync: Loading DB in memory
1734:S 11 May 2020 16:54:42.833 * MASTER <-> REPLICA sync: Finished with success

对于线上做读写分离的场景, 从节点也负责响应读命令。 如果此时从节点正出于全量复制阶段或者复制中断, 那么从节点在响应读命令可能拿到过期或错误的数据。 对于这种场景, Redis复制提供了slave-serve-stale-data参数, 默认开启状态。 如果开启则从节点依然响应所有命令。 对于无法容忍不一致的应用场景可以设置no来关闭命令执行, 此时从节点除了info和slaveof
命令之外所有的命令只返回“SYNC with master in progress”信息。

9) 从节点成功加载完RDB后, 如果当前节点开启了AOF持久化功能,它会立刻做bgrewriteaof操作, 为了保证全量复制后AOF持久化文件立刻可用

全量复制是一个非常耗时费力的操作。 它的时间开销主要包括:
·主节点bgsave时间
·RDB文件网络传输时间。
·从节点清空数据时间。
·从节点加载RDB的时间。
·可能的AOF重写时间。
例如我们线上数据量在6G左右的主节点, 从节点发起全量复制的总耗时在2分钟左右。 因此当数据量达到一定规模之后, 由于全量复制过程中将进行多次持久化相关操作和网络数据传输, 这期间会大量消耗主从节点所在服务器的CPU、 内存和网络资源。 所以除了第一次复制时采用全量复制在所难免之外, 对于其他场景应该规避全量复制的发生。 正因为全量复制的成本
问题, Redis实现了部分复制功能。
 

​redis全量一张图总结如下​


Redis 全量复制详解_redis_02