新从库第一次连主库,或者补不上差量时,要做一次全量同步:主库把当前的数据集做成 RDB 传过去,从库加载。这几步各花多久、期间主库的新写入去哪了?这篇在 100 万个 key 的数据集上,把同步过程的日志、采样和最终数据对账都记下来(这里用磁盘方式;无盘方式见第 58 篇)。
t(s) link sync中 已接收 总量 loading 已加载 0.00 down 0 0 0 0 0 0.05 down 1 0 -1 0 0 0.33 down 1 0 -1 0 0 0.63 down 1 24889081 24889081 1 1048575 0.93 down 1 24889081 24889081 1 14680063 1.22 up 0 0 0 0 0
第一列是相对 REPLICAOF 的时间。BGSAVE 阶段,master_sync_in_progress 是 1 而总量是 -1;RDB 传完之后 master_sync_read_bytes 等于总量,同时 loading 变成 1,loading_loaded_bytes 往上涨;加载完成 master_link_status 才变成 up。
+ 0.000s [从] MASTER <-> REPLICA sync started + 0.001s [主] Replica 127.0.0.1:7169 asks for synchronization + 0.001s [主] Starting BGSAVE for SYNC with target: disk + 0.567s [主] Background saving terminated with success + 0.567s [从] MASTER <-> REPLICA sync: receiving 24889081 bytes from master to disk + 0.589s [主] Synchronization with replica 127.0.0.1:7169 succeeded + 0.593s [从] MASTER <-> REPLICA sync: Loading DB in memory + 0.597s [从] MASTER <-> REPLICA sync: Flushing old data + 1.181s [从] Done loading RDB, keys loaded: 1000001, keys expired: 0. + 1.181s [从] MASTER <-> REPLICA sync: Finished with success
主库在 +0.001 s 开始 BGSAVE,0.57 s 后结束;RDB 的传输几乎瞬间;从库在 0.593 s 开始加载,1.18 s 完成。其中最耗时的两段:主库 BGSAVE(0.57 s)和从库加载(0.59 s)。本机回环上传输不是瓶颈;跨机器的网络带宽会让「传输」这一段变长——这里没有测。
dump.rdb: 24.9 MB(主库 dir 里真实存在) 同步期间主库写入了 391 个 live:* key;同步结束后 dbsize 主/从 = 1000391 / 1000391 主库 stats: sync_full = 1 主库 client_recent_max_output_buffer = 20504 字节(同步期间给从库缓冲的增量命令)
同步开始后我用另一个线程持续往主库写 live:* key(391 个)。这些命令在 RDB 生成之后,先缓冲在主库给该从库的输出缓冲区,RDB 加载完成后再发给从库。最终 dbsize 主 1000391、从 1000391,一致,等于 100 万加 391。从库日志里 keys loaded = 1000001:RDB 装的是 fork 那一刻的数据(其中已含 1 个 live key),其余 390 个是缓冲的增量命令补上的。