bigywater.tech
Redis · 54

全量同步中的 RDB 传输

新从库第一次连主库,或者补不上差量时,要做一次全量同步:主库把当前的数据集做成 RDB 传过去,从库加载。这几步各花多久、期间主库的新写入去哪了?这篇在 100 万个 key 的数据集上,把同步过程的日志、采样和最终数据对账都记下来(这里用磁盘方式;无盘方式见第 58 篇)。

1.18 s
100 万 key 全量同步总耗时(BGSAVE 0.57 s + 加载 0.59 s)
24.9 MB
RDB 文件大小(内存 159 MB;value 高度可压缩)
20504 B
同步期间为从库缓冲的增量命令峰值(期间写入 391 条)

采样:从库在每个阶段的样子

每 50 ms 读一次从库的 INFO
实测 · 本机执行输出
  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 个是缓冲的增量命令补上的。

分步演示:全量同步的五个阶段

全量同步中的 RDB 传输
当前阶段

    本文用到的工具与边界

    • 本机 macOS 27 / Redis 8.10.2 独立实例(本机回环端口,save 关闭),redis-cli 风格输出由自写的 RESP 客户端打印;计时用 time.perf_counter,数字每次运行会有小幅抖动。主库 repl-diskless-sync no(磁盘方式),100 万个 key,每个 value 是 100 个 v;从库在同一台机器
    • 没有验证:跨机器网络下的传输耗时、value 不可压缩(如随机数据)时的 RDB 大小、repl-timeout 与 client-output-buffer-limit replica 在同步过久时触发断开的情形(本次没有触发)
    京ICP备2026067502号-1京公网安备11010502063487号