最近跟数据恢复杠上了,这不又来一例。对于备份复原的问题其实我在6年多以前就写过,其中大部分探讨放在明天依然实用。
案例介绍
某用户应用了MongoDB 4.0,数据库中的一个表因为drop操作导致数据全副失落。但因为库自身很小,而oplog空间足够大,所以从建库至今的所有操作都尚在oplog中没有被回收。基于这种状况,尽管他们没有全量备份,咱们依然能够通过残缺重放oplog来找回所有失落的数据。所以咱们的操作是:
导出oplog;
寻找drop产生的工夫戳;
重放到drop前一刻;
将复原的数据dump/restore到生产库;
步骤4属于基本操作就不具体叙述了,次要来看后面3步。
复原步骤
2.1 导出oplog
这一步实际上特地简略。oplog位于local.oplog.rs汇合中,咱们能够应用mongodump间接导出,导出节点能够是主节点或从节点。根本模式是:
mongodump --host <host>:<port> -d local -c oplog.rs -u <user> --authenticationDatabase <adb>
失去如下输入:
> tree dumpdump└── local ├── oplog.rs.bson └── oplog.rs.metadata.json
1 directory, 2 files
咱们须要的就是oplog.rs.bson。
2.2 寻找截止工夫戳
进行重放的要害是要先找出重放截止到哪条oplog。这里有两种方法:
计划1
从oplog.rs.bson中搜寻关键字drop。
> bsondump dump/local/oplog.rs.bson | grep drop{"ts":{"$timestamp":{"t":1646056645,"i":1}},"t":{"$numberLong":"1"},"h":{"$numberLong":"7307295890643732087"},"v":{"$numberInt":"2"},"op":"c","ns":"test.$cmd","ui":{"$binary":{"base64":"9sakiEOMS2qjwBZ5O0mQjQ==","subType":"04"}},"wall":{"$date":{"$numberLong":"1646056645661"}},"o":{"drop":"survey"}}
如果屡次呈现drop记录,则要本人留神分别哪条是你想要的那条。而后留神记录中{"t":1646056645,"i":1}是咱们要截止到的工夫戳,前面将会用到这个数据。
另外留神如果oplog较多时该方法可能会耗时较长。
计划2
从local.oplog.rs中查问。这种查询方法通常会比计划1快,但须要在原始零碎上运行查问,可能造成肯定的累赘。如果零碎自身压力曾经较大,则要留神避开业务高峰期。另外也能够在从节点上执行查问以避开压力最大的主节点。这里要留神的是每个节点上保留的oplog可能不一样多,但肯定是统一的。例如,某个节点上的oplog有1,2,3,4,5共计5条,其余节点上可能只有:
2,3,4,5
3,4,5
4,5
5
这种状况通常是因为从节点是起初加进集群里导致的。那么想要查问时,能够应用:
> use local> db.oplog.rs.find({"o.drop": {$exists: true}}).sort({$natural: -1}).limit(1);{ "ts" : Timestamp(1646056729, 1), "t" : NumberLong(1), "h" : NumberLong("6882491835596436855"), "v" : 2, "op" : "c", "ns" : "test.$cmd", "ui" : UUID("a98cba5a-066b-46fe-92a9-d122386dba5d"), "wall" : ISODate("2022-02-28T13:58:49.167Z"), "o" : { "drop" : "survey" } }
同样留神Timestamp(1646056729, 1)是咱们将要用到的截止工夫戳。
2.3 重放oplog
mongorestore自身是用来复原bson文件的同时顺便重放oplog的。当初咱们没有bson要复原,只有oplog要重放,所以须要点小花招来坑骗mongorestore,那就是用一个空文件夹:
mkdir emptymongorestore --host <host>:<port> -u <user> --authenticationDatabase <adb> \ --oplogReplay \ --oplogFile dump/local/oplog.rs.bson \ --oplogLimit 1646056729:1 \ empty/
留神:这里应该在一个新的实例上实现重放操作。
重放实现后,你就领有了一份截止到drop操作前的残缺数据。
改良计划
下面的步骤尽管能够实现工作,但有些节约。因为失落的只有一个表,咱们却复原了整个数据库,耗费了不必要的工夫。有没有方法只复原失落的那一个表呢?从原理来讲是能够办到的,那就是只重放这个表上的oplog,那么只须要在导出oplog的时候做个过滤就能够办到了:
mongodump --host <host>:<port> -d local -c oplog.rs -u <user> --authenticationDatabase <adb> -q '{"ns": "test.survey"}'
后续步骤没有什么差别,就不再赘述了。然而这样的做法有个bug,那就是事务。我一开始也栽在了这个问题上。事务会把多条操作放在一条oplog里,以此来保障事务的原子性。比方如下事务操作:
var mongo = db.getMongo();var session = mongo.startSession();session.startTransaction();var coll = session.getDatabase("test").getCollection("survey");coll.insertOne({y: 1});coll.insertOne({y: 2});coll.insertOne({y: 3});session.commitTransaction();
其产生的oplog是这样的:
{ "ts": Timestamp(1646057834, 1), "t": NumberLong(1), "h": NumberLong("-2362908976881142089"), "v": 2, "op": "c", "ns": "admin.$cmd", "wall": ISODate("2022-02-28T14:17:14.189Z"), "lsid": { "id": UUID("02ca1f7e-f451-4ec3-946f-cf307c0d03b7"), "uid": BinData(0, "47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=") }, "txnNumber": NumberLong(1), "stmtId": 0, "prevOpTime": { "ts": Timestamp(0, 0), "t": NumberLong(-1) }, "o": { "applyOps": [{ "op": "i", "ns": "test.survey", "ui": UUID("04a8b634-4048-48a6-b358-9a879c1a20ed"), "o": { "_id": ObjectId("621cd969a3a94c2e74b595c5"), "y": 1 } }, { "op": "i", "ns": "test.survey", "ui": UUID("04a8b634-4048-48a6-b358-9a879c1a20ed"), "o": { "_id": ObjectId("621cd969a3a94c2e74b595c6"), "y": 2 } }, { "op": "i", "ns": "test.survey", "ui": UUID("04a8b634-4048-48a6-b358-9a879c1a20ed"), "o": { "_id": ObjectId("621cd969a3a94c2e74b595c7"), "y": 3 } }] }}
可见这里的{"ns": "admin.$cmd"}并不在test.survey上,所以下面的过滤方法会把事务产生的数据都排除在外,就会造成一部分数据失落。解决办法也很简略,批改一下过滤条件:
mongodump --host <host>:<port> -d local -c oplog.rs -u <user> --authenticationDatabase <adb> -q '{"$or": [{"ns": "test.survey"}, {"o.applyOps.ns": "test.survey"}]}'
结束语
这个案例是个很极其的状况,所以不要想着抄作业,你简直肯定不会遇到雷同的场景。但复原的原理却是相通的,无论何种备份复原都是“全量”+“增量”的做法,只有你了解了原理,剩下的就是入手尝试而已。
对于作者:张耀星
MongoDB中文社区常委会委员,论坛联席主席。
MongoDB公司北亚区首席技术咨询服务参谋。在MongoDB的开发、利用和咨询服务方面,领有多年的丰盛实践经验。
作为MongoDB认证专家,已经为不同行业的各类大型客户提供过培训、性能调优、架构设计等各类技术及咨询服务,颇得广大客户信赖。