MongoDB的备份其实算是一个基本操作,最近总是有人问起,看来很多人对这里还不太熟悉。为了避免一次又一次地重复解释,特总结成一篇博客供后来者查阅。如有不尽正确之处请指正。
?
1. 内建方法
?
?
不用多做解释,几乎对任何
数据库都有用,简单粗暴。但像多数数据库一样,这个操作必须在mongod实例停止的情况下进行才能保证你得到的是正确状态下的数据库。否则在备份过程中如果有写操作,可能造成备份到的库处于非正常状态而不可使用。必须停止数据库这一点就造成了这个方法的可用性非常低,使用场景有限。
?
1.2 mongodump/mongorestore
?
我不打算细说这两个命令如何使用,因为介绍这两个命令的文章网上已经一大堆了,大家可以轻松从别处或者官方文档中找到说明。不想细说的另一个原因也是希望看到这里的读者能够养成独立解决问题的能力,不要对所谓的“高手”产生依赖,遇到问题独立思考独立解决,这将是你今后的道路上必不可少的技能之一。
?
下面介绍一些别人说得相对少的东西。
?
1.2.1 除了mongodump/mongorestore之外还有一对组合是mongoexport/mongoimport
?
区别在哪里?
?
mongoexport/mongoimport导入/导出的是JSON格式,而mongodump/mongorestore导入/导出的是BSON格式。
JSON可读性强但体积较大,BSON则是二进制文件,体积小但对人类几乎没有可读性。
在一些mongodb版本之间,BSON格式可能会随版本不同而有所不同,所以不同版本之间用mongodump/mongorestore可能不会成功,具体要看版本之间的兼容性。当无法使用BSON进行跨版本的数据迁移的时候,使用JSON格式即mongoexport/mongoimport是一个可选项。跨版本的mongodump/mongorestore个人并不推荐,实在要做请先检查文档看两个版本是否兼容(大部分时候是的)。
JSON虽然具有较好的跨版本通用性,但其只保留了数据部分,不保留索引,账户等其他基础信息。使用时应该注意。
总之,这两套工具在实际使用中各有优势,应该根据应用场景选择使用(好像跟没说一样)。但严格地说,mongoexport/mongoimport的主要作用还是导入/导出数据时使用,并不是一个真正意义上的备份工具。所以这里也不展开介绍了。
?
1.2.2 mongodump有一个值得一提的选项是--oplog
?
注意这是replica set或者master/slave模式专用(standalone模式运行mongodb并不推荐)。
?
--oplog use oplog for taking a point-in-time snapshot
?
看英文说明好牛B的样子,point-in-time快照哦,我第一次看到这句话的时候的理解是它可以让数据库回到这段时间中的任意一个时间点的状态,美了好一阵。但实际上并不是。它的实际作用是在导出的同时生成一个oplog.bson文件,存放在你开始进行dump到dump结束之间所有的oplog。这个东西具体有什么用先卖个关子。用图形来说明下oplog.bson的覆盖范围:
?
?
为了后面的讲解不至于把人说晕,进一步说明之前先解释一下什么是oplog及其相关概念。官方提供的文档其实已经很全面地做了解释,点击查看中文文档或英文文档。
?
简单地说,在replica set中oplog是一个定容集合(capped collection),它的默认大小是磁盘空间的5%(可以通过--oplogSizeMB参数修改),位于local库的db.oplog.rs,有兴趣可以看看里面到底有些什么内容。其中记录的是整个mongod实例一段时间内数据库的所有变更(插入/更新/删除)操作。当空间用完时新记录自动覆盖最老的记录。所以从时间轴上看,oplog的覆盖范围大概是这样的:
?
?
其覆盖范围被称作oplog时间窗口。需要注意的是,因为oplog是一个定容集合,所以时间窗口能覆盖的范围会因为你单位时间内的更新次数不同而变化。想要查看当前的oplog时间窗口预计值,可以使用以下命令:
?
test:PRIMARY> rs.printReplicationInfo()
configured oplog size: ? 1561.5615234375MB <--集合大小
log length start to end: 423849secs (117.74hrs) <--预计窗口覆盖时间
oplog first event time: ?Wed Sep 09 2015 17:39:50 GMT+0800 (CST)
oplog last event time: ? Mon Sep 14 2015 15:23:59 GMT+0800 (CST)
now: ? ? ? ? ? ? ? ? ? ? Mon Sep 14 2015 16:37:30 GMT+0800 (CST)
oplog有一个非常重要的特性——幂等性(idempotent)。即对一个数据集合,使用oplog中记录的操作重放时,无论被重放多少次,其结果会是一样的。举例来说,如果oplog中记录的是一个插入操作,并不会因为你重放了两次,数据库中就得到两条相同的记录。这是一个很重要的特性,也是后面这些操作的基础。
?
回到主题上来,看看oplog.bson到底有什么作用。首先要明白的一个问题是数据之间互相有依赖性,比如集合A中存放了订单,集合B中存放了订单的所有明细,那么只有一个订单有完整的明细时才是正确的状态。假设在任意一个时间点,A和B集合的数据都是完整对应并且有意义的(对非关系型数据库要做到这点并不容易,且对于MongoDB来说这样的数据结构并非合理。但此处我们假设这个条件成立),那么如果A处于时间点x,而B处于x之后的一个时间点y时,可以想象A和B中的数据极有可能不对应而失去意义。
?
再回来看mongodump的操作。mongodump的进行过程中并不会把数据库锁死以保证整个库冻结在一个固定的时间点,这在业务上常常是不允许的。所以就有了dump的最终结果中A集合是10点整的状态,而B集合则是10点零1分的状态这种情况。这样的备份即使恢复回去,可以想象得到的结果恐怕意义有限。那么上面这个oplog.bson的意义就在这里体现出来了。如果在dump数据的基础上,再重做一遍oplog中记录的所有操作,这时的数据就可以代表dump结束时那个时间点(point-in-time)的数据库状态。
?
这个结论成立的重要条件就是幂等性:已存在的数据,重做oplog不会重复;不存在的数据重做oplog就可以进入数据库。所以当做完截止到某个时间点的oplog时,数据库就恢复到了截止那个时间点的状态。
?
来看看mongorestore的选项。跟oplog相关的选项有--oplogReplay和--oplogLimit。第一个选项顾名思义,可以重放oplog.bson中的操作内容。第二个选项