美文网首页
MongoDB无法启动的情况下恢复数据(二)

MongoDB无法启动的情况下恢复数据(二)

作者: Go是世界上最好的语言 | 来源:发表于2019-06-18 12:28 被阅读0次

    之前写过一篇的文章MongoDB无法启动的情况下恢复数据(一),介绍了几种从无法启动的 MongoDB 节点恢复数据的方法,主要包括:

    如果配置了副本集多节点,则从其他节点恢复(强烈建议重要的数据至少要存2份)

    从最近的备份集恢复,一般重要的生产数据,需要对数据进行持续的全量/增量备份

    repair 模式恢复,如果元数据本身有问题,repair 模式也是无法工作的;

    通过 WiredTiger 自带工具分析,对元数据损坏的情况也使用,能尽可能多的恢复数据。

    通过分析 BSON 数据来提取恢复数据,但这个只对没有压缩的 mmapv1 引擎有效,默认 WiredTiger 会开启 snappy 压缩,无法通过分析 BSON 来提取出数据。

    其中方法1-3比较简单,第4种方法对 WiredTiger 引擎的原理不了解,可能完全无从下手,本文将详细介绍如何通过 WiredTiger 的工具来提取有效数据。

    背景知识

    每个 MongoDB 的集合/索引都对应一个 WiredTiger Table; 集合名跟 Table 名的映射关系保存在元数据里,只有通过这部分元数据,才能获得这个映射关系。

    集合的数据对应 collecton-uniqueid-hash.wt 文件

    索引的数据对应 index-uniqueid-hash.wt

    MongoDB 所有集合的元数据,都存在一个特殊的 WiredTiger Table 里,名字叫 _mdb_catalog;这里可以看出,MongoDB 的元数据,对 WiredTiger 来说其实也只是普通数据。

    只要单个表的数据有效,通过 WiredTiger 的wt工具可以将其提取出来。默认 MongoDB 的源码里不会编译出 wt 工具,可以自行下载 WiredTiger 源码编译,接下来的介绍假设你已经编译出了 wt 工具。

    恢复单个集合

    假设你的数据库只有很少的集合,根据集合的大小,你可能很容易判断出集合名跟 WiredTiger 文件名的对应关系,比如

    somedb.collection ===>  somedb/collection-10--6822964274931136278(如果没有指定 directoryPerDB 的选项,则没有 somedb/前缀

    只要这个这个集合的数据还是完整的,没有被损坏,我们就可以通过如下步骤来恢复

    Step1: 通过 wt 工具将集合数据 dump 到文件

    ./wt -v -h some_db_home -C"extensions=[./ext/compressors/snappy/.libs/libwiredtiger_snappy.so]"-Rdump-f collection.dumpsomedb/collection-10--6822964274931136278

    此时,这个集合的数据就已经导出到 collection.dump 文件了,如果这一步出错,说明这个文件 WiredTiger 已经无法解析了,则无法恢复了。

    Step2: 在新的实例上创建一个临时集合

    mkdir some_dest_db_home

    mongod --dbpath some_dest_db_home --port some_port

    mongo --port some_port

    > use somedb

    > db.createCollection("collection")// 创建临时集合

    > db.collection.stats().uri// 查看该集合对应的 WiredTiger 表名

    假设临时集合创建后,其在新的临时实例上集合名与 WiredTiger 表名对应关系如下

    somedb.collection ===> somedb/collection-2--6822964274931136278(如果没有指定 directoryPerDB 的选项,则没有 somedb/前缀

    Step3: 将 dump 出的数据 load 到临时集合

    停掉临时实例,然后将 Step1 里 dump 的数据 load 到临时集合

    ./wt -v -h some_dest_db_home -C"extensions=[./ext/compressors/snappy/.libs/libwiredtiger_snappy.so]"-Rload -f  collection.dump-r somedb/collection-2--6822964274931136278

    这时在目标实例上,访问 somedb.collection 时,访问的数据就是从「已经损坏的源实例」上 somedb.collection 的数据,只不过这个实例的 id 索引、统计元数据等是无法匹配的,但这并不影响全表扫描的数据访问。

    Step4:mongodump/mongorestore 临时集合,修正数据统计信息、索引信息

    通过 mongodump 从目标实例将 somedb.collection 备份出来,mongodump 只会触发对集合数据的顺序访问。

    然后通过 mongorestore 重新导入,restore 后的数据即为恢复的目标数据。

    恢复大量集合

    上面介绍了如何恢复单个集合,如果损坏的 MongoDB

    里有大量的集合,一个个按上面的流程恢复要搞到猴年马月了;要想自动化,需要解决的关键问题就是如果确定 MongoDB 集合名 与

    WiredTiger 表名的映射关系,这里只需要稍加修改 MongoDB 源码,可以让 损坏的mongod 在 repair

    模式下把映射关系输出

    diff --git a/src/mongo/db/storage/kv/kv_database_catalog_entry.cpp b/src/mongo/db/storage/kv/kv_database_catalog_entry.cpp

    index91afa40026..523cb1fa95100644

    --- a/src/mongo/db/storage/kv/kv_database_catalog_entry.cpp

    +++ b/src/mongo/db/storage/kv/kv_database_catalog_entry.cpp

    @@-260,6+260,8@@voidKVDatabaseCatalogEntry::initCollection(OperationContext* opCtx,

    conststd::stringident = _engine->getCatalog()->getCollectionIdent(ns);

    +log() <<"metadata mapping "<< ns <<" "<< ident;

    +

        RecordStore* rs;

    if(forRepair) {

    // Using a NULL rs since we don't want to open this record store before it has been

    Step1: 获取损坏实例的MongoDB 集合名 与 WiredTiger 表名的映射关系,例如

    somedb.collection1collection-2--4775156767705741267

    somedb.collection2collection-4--4775156767705741267

    ....

    Step2:根据上述映射关系,将集合数据逐个 dump

    写个 shell 脚本很容易做到自动化,导出的文件名可以跟集合名保持一致,用于区分

    Step3:创建目标实例,并预先创建好所有的集合

    写个 js 脚本,通过 mongo shell 批量创建

    Step4: 获取目标实例的MongoDB 集合名 与 WiredTiger 表名的映射关系,例如

    somedb.collection1collection-6--4335156767705741253

    somedb.collection2collection-8--4335156767705741253

    ....

    Step5:将 dump 数据逐个 load 到 目标实例

    跟 Step2 类似,需要写个 shell 脚本

    Step6: 对整个目标实例(或部分 DB)进行 mongodump/mongorestore

    修正 id 索引、统计信息等

    相关文章

      网友评论

          本文标题:MongoDB无法启动的情况下恢复数据(二)

          本文链接:https://www.haomeiwen.com/subject/eutfqctx.html