2. MongoDB存储引擎与持久化机制
要理解 MongoDB 的备份恢复,不能只停留在 mongodump 和 mongorestore 的命令层面,而必须看清数据在磁盘上究竟以什么形态存在、哪些文件是“真相”、哪些文件只是“过程记录”。MongoDB 默认使用 WiredTiger 存储引擎,它把数据组织在数据文件、journal 日志、检查点以及复制集特有的 oplog 之中。这四类对象承担着完全不同的职责,也决定了不同备份方式的边界。
一、WiredTiger 的磁盘布局:数据文件与检查点
在 WiredTiger 中,每个集合和索引默认各自对应一个独立的表文件,存放在数据库目录下,命名形如 collection-*.wt 与 index-*.wt。这些 .wt 文件才是数据的最终归属地。但 WiredTiger 并不会在每次写入时立刻把页写回这些文件,而是先在内存缓存中修改,再通过检查点(checkpoint)机制把某一时刻的一致快照刷写到磁盘。
检查点可以理解为“给整个存储引擎拍一张带时间戳的全量快照”。执行检查点时,WiredTiger 会把内存中所有脏页落盘,并在元数据中记录一个 checkpoint 条目,指向该时刻各数据文件的有效版本。MongoDB 默认大约每 60 秒触发一次检查点,也可由 storage.wiredTiger.engineConfig.checkpointSizeMB 等参数影响其行为。检查点完成后,磁盘上的数据文件就代表了一个自洽的、可被恢复的起点。
关键点在于:检查点不是实时的。两次检查点之间发生的写入,只存在于内存和 journal 中。如果此时断电,数据文件还停留在上一个检查点,最新写入尚未进入 .wt 文件。
二、journal 日志:检查点之间的“补丁”
为了弥补检查点的时间窗口,WiredTiger 引入了 journal(日志)。journal 采用预写日志(WAL)思想:任何修改在写入数据文件之前,先以追加方式写入 journal 文件。MongoDB 默认开启 journal,日志文件位于 journal/ 目录,单个文件约 100MB,写满后轮转。
journal 记录的是“逻辑上如何修改”,而不是完整的数据页。它让 MongoDB 在崩溃后能够重放(replay)自上一个检查点以来尚未落盘的操作,把数据文件推进到崩溃前的一致状态。因此恢复流程可以概括为:先加载最近一次检查点,再重放 journal 中该检查点之后的记录。
三、oplog:复制集层面的操作流水
在复制集中,主节点会把所有影响数据的写操作记录到一个特殊的 capped collection——local.oplog.rs 中,这就是 oplog。oplog 是幂等的、可重放的逻辑操作序列,从节点通过持续拉取并应用 oplog 来保持与主节点一致。
oplog 与 journal 容易混淆,但二者层次不同:journal 是存储引擎内部的物理/逻辑日志,服务于单节点崩溃恢复;oplog 是复制集层面的逻辑操作日志,服务于节点间数据同步。oplog 有固定大小(由 replSetResizeOplog 或启动参数决定),是环形覆盖的,旧记录会被新记录挤出。这意味着 oplog 只能覆盖一个有限的时间窗口,超出窗口的从节点将无法增量同步,必须重新做全量初始同步。
四、四类对象的关系与备份含义
把上述对象放在一起,就能看清备份恢复的底层对象关系:数据文件是最终状态,检查点是数据文件的某个一致快照点,journal 是检查点之后到崩溃前的增量补丁,oplog 则是复制集维度上可被其他节点重放的变更流。下图展示了它们在同一节点上的层次与数据流向。
从备份视角看,这张图给出了三条重要结论。第一,物理文件级备份(如文件系统快照、mongodump --oplog 之外的冷备)必须保证数据文件与 journal 的一致性,否则恢复时可能缺少检查点之后的增量。第二,逻辑备份(mongodump)导出的是 BSON 文档,它绕过了存储引擎细节,但无法保留 oplog 的精确时间点,因此复制集场景下需要配合 --oplog 才能获得某个时间点的一致性快照。第三,oplog 是增量恢复与时间点恢复(PITR)的关键,只要 oplog 窗口覆盖目标时间点,就可以从全量备份出发,重放 oplog 到指定时刻。
五、参数与观察点
在实际运维中,可以通过以下方式观察这些对象的状态。查看检查点与 journal 相关统计:
db.serverStatus().wiredTiger
db.serverStatus().wiredTiger.log // journal 相关指标
db.serverStatus().oplog // 复制集下查看 oplog 窗口
rs.printReplicationInfo() // 查看 oplog 大小与时间跨度
其中 rs.printReplicationInfo() 会输出 oplog 的已用时间窗口,例如“configured oplog size: 2048MB,log length start to end: 3600secs”,这直接决定了 PITR 能回溯多远。若窗口只有一小时,那么任何超过一小时的恢复目标都无法仅靠 oplog 完成。
理解这四类对象的层次与流向,后续选择冷备、热备、逻辑备份还是快照备份时,才能准确判断每种方式覆盖了哪些对象、遗漏了哪些对象,以及恢复时究竟能回到哪一个一致状态。