RDB 将某一时刻的数据集保存为快照。SAVE 在主线程执行保存,会阻塞命令处理;BGSAVE 在常见 Unix 部署中通过 fork 创建子进程,由子进程生成快照,主进程继续服务。后台保存减少长时间的文件写入阻塞,但不等于整个过程毫无延迟。
fork 为什么不会立刻复制整个数据集?
fork 后父子进程最初共享物理页,并拥有各自的地址空间映射。操作系统采用写时复制:主进程之后修改共享页时,为写入方分配新页,子进程仍看到快照时刻的旧内容。因此子进程可以保存一致的旧视图,而父进程接收新写入。
举例:开始快照时 stock=100,主进程随后把它改成 99。子进程保存的是快照视图中的 100,后续 AOF 或复制增量负责记录新的修改。不能把 BGSAVE 想成子进程不断读取父进程随时变化的“最新内存”。
fork 自身需要复制页表等内核工作,数据集越大,其耗时越值得关注。快照期间若写入密集,大量页触发 COW,额外内存可能显著增长;一个很小的字段修改也可能使其所在内存页复制。磁盘慢会延长子进程存活时间,从而扩大 COW 累计窗口。
RDB 的优势与风险
RDB 文件较紧凑,适合备份和相对快速的数据集恢复。代价是两次成功快照之间的修改可能丢失,具体损失量与快照周期和故障时刻有关。备份应复制完整且生成成功的快照,并验证恢复过程,不能只看目录里有一个文件。
常见追问
BGSAVE 会阻塞多久?
主要关注 fork 阶段的暂停,以及后续资源竞争对延迟的影响;后台写文件不是全程阻塞主线程。实际耗时应查看 INFO persistence 与延迟指标。
快照时内存会直接翻倍吗?
不会必然立刻翻倍。增长由被修改的共享页、页表和进程开销决定,写密集时则可能接近很高的额外需求。容量规划要按峰值留余量。
无盘复制就没有 COW 开销了吗?
不一定。无盘复制减少中间磁盘文件步骤,但生成快照的后台过程仍可能使用 fork 与 COW;它主要改变快照输出路径。
把 RDB 周期缩短就能做到零丢失吗?
不能。快照之间仍有窗口,频繁生成快照还增加资源消耗。需要结合 AOF、复制和业务持久化设计确定可接受的恢复点。