MongoDB無法啟動的情況下恢復(fù)數(shù)據(jù)(一)

使用 Wiredtiger 存儲引擎的 MongoDB 無法啟動,數(shù)據(jù)能否恢復(fù)回來?

問題出現(xiàn)的場景是「mongod磁盤寫滿了,導(dǎo)致進(jìn)程 crash」,嘗試重新啟動,結(jié)果 wiredtiger 報(bào)錯,錯誤信息類似如下,說明此時 MongoDB 數(shù)據(jù)文件已經(jīng)損壞。


2017-03-28T22:06:05.315-0500 W -? ? ? ? [initandlisten] Detected unclean shutdown - /data/mongodb/mongod.lock is not empty.

2017-03-28T22:06:05.315-0500 W STORAGE? [initandlisten] Recovering data from the last clean checkpoint.

2017-03-28T22:06:05.324-0500 I STORAGE? [initandlisten] wiredtiger_open config: create,cache_size=13G,session_max=20000,eviction=(threads_max=4),statistics=(fast),log=(enabled=true,archive=true

,path=journal,compressor=snappy),file_manager=(close_idle_time=100000),checkpoint=(wait=60,log_size=2GB),statistics_log=(wait=0),

2017-03-28T22:06:05.725-0500 E STORAGE? [initandlisten] WiredTiger (0) [1454119565:724960][1745:0x7f2ac9534bc0], file:WiredTiger.wt, cursor.next: read checksum error for 4096B block at offset 6

799360: block header checksum of 1769173605 doesn't match expected checksum of 4176084783

2017-03-28T22:06:05.725-0500 E STORAGE? [initandlisten] WiredTiger (0) [1454119565:725067][1745:0x7f2ac9534bc0], file:WiredTiger.wt, cursor.next: WiredTiger.wt: encountered an illegal file form

at or internal value

2017-03-28T22:06:05.725-0500 E STORAGE? [initandlisten] WiredTiger (-31804) [1454119565:725088][1745:0x7f2ac9534bc0], file:WiredTiger.wt, cursor.next: the process must exit and restart: WT_PANI

C: WiredTiger library panic

2017-03-28T22:06:05.725-0500 I -? ? ? ? [initandlisten] Fatal Assertion 28558


MongoDB 3.2及以后的版本已經(jīng)很少會出現(xiàn)這樣的問題,至少從我接觸 MongoDB 到現(xiàn)在還沒實(shí)際遇到過這個問題,不過既然問題已經(jīng)發(fā)生,我們來看看遇到這種情況應(yīng)該怎么恢復(fù)數(shù)據(jù)?

如何恢復(fù) MongoDB 數(shù)據(jù)?

第一招: 從復(fù)制集其他節(jié)點(diǎn)同步數(shù)據(jù)

MongoDB 通過復(fù)制集能保證高可靠的數(shù)據(jù)存儲,通常生產(chǎn)環(huán)境建議使用「3節(jié)點(diǎn)復(fù)制集」,這樣即使其中一個節(jié)點(diǎn)崩潰了無法啟動,我們可以直接將其數(shù)據(jù)清掉,重新啟動后,以全新的 Secondary 節(jié)點(diǎn)加入復(fù)制集,它會自動的同步數(shù)據(jù),這樣也就達(dá)到了恢復(fù)數(shù)據(jù)的目的。

然而不幸的是,該用戶的 MongoDB 實(shí)例 只部署了一個節(jié)點(diǎn) ... 我只能呵呵了 ...

第二招:從最近的一個備份集恢復(fù)數(shù)據(jù)

有的時候可能出現(xiàn)一些極端的case,比如遇到自然災(zāi)害,復(fù)制集所有節(jié)點(diǎn)都掛了(或者像上面的用戶這樣,你的復(fù)制集只部署一個節(jié)點(diǎn)...),這時第一招就沒法用了。

此時,如果靠譜的你剛好對數(shù)據(jù)做了備份,此時就排上用場了,比如你每天對 MongoDB 做一次全量備份,那么你就可以把數(shù)據(jù)恢復(fù)到最近一天的數(shù)據(jù)了;如果你更靠譜的還對數(shù)據(jù)做了增量本分,能恢復(fù)的數(shù)據(jù)就更多了。

但是可想而知,這個用戶既然能部署一個「只有單個節(jié)點(diǎn)的復(fù)制集」,肯定也不會想到去對數(shù)據(jù)庫進(jìn)行備份了 ...

第三招: repair 模式啟動 MongoDB

當(dāng) MongoDB 無法啟動時,通常是因?yàn)閿?shù)據(jù)文件出現(xiàn)了不一致,mongod 支持以 repair 的模式啟動,mongod 會盡可能的嘗試自己去修復(fù)數(shù)據(jù)的不一致狀態(tài),修復(fù)過程中盡可能多的保留有效的數(shù)據(jù)。

但 repair 也不是對所有的場景都有效,repair 會先加載 MongoDB 所有的集合信息,然后針對每個集合來 repair,如果存儲元數(shù)據(jù)的數(shù)據(jù)文件損壞,repair 也是沒法工作的。

mongod --repair // 用戶嘗試按這種方式啟動,仍然報(bào)相同的錯誤

第四招:使用 wireditger 工具恢復(fù)

以上3招都不行,我的第一想法就是通過 wiredtiger 的 salvage 功能去盡可能的恢復(fù)數(shù)據(jù)(salvage 可翻譯為數(shù)據(jù)打撈,即針對一個wt的數(shù)據(jù)文件,盡可能多的從中提取有效的數(shù)據(jù)),本來是想寫個工具來做這個事情。不過調(diào)研了一下發(fā)現(xiàn)

1. repair 模式啟動,實(shí)現(xiàn)時也是調(diào)用的 wiredtiger 的 salvage 接口實(shí)現(xiàn)。

2. wireditger 自帶的一個命令行工具 wt,包含了 salvage 的功能。

3. 找到一篇使用 wt 工具恢復(fù) MongoDB 數(shù)據(jù)的文章,寫的非常贊。

網(wǎng)友總結(jié)的使用 wiredtiger 工具 wt 恢復(fù)數(shù)據(jù)的方法原理很簡單,就是通過恢復(fù) wiredtiger 數(shù)據(jù)文件來恢復(fù)MongoDB數(shù)據(jù),我實(shí)驗(yàn)了一下,的確可行,而且原文的步驟介紹已經(jīng)非常詳細(xì),這里就不再贅述。需要注意的是

MongoDB 3.2 最新版本已經(jīng)是了 wiredtiger 2.8,所以編譯 wt 工具時,可以下載 2.8 版本的 wiredtiger 源代碼。

MongoDB 默認(rèn)會對集合數(shù)據(jù)進(jìn)行 snappy 壓縮,所以一定要確保 snappy 正確安裝,在執(zhí)行 wt 工具時,通過擴(kuò)展的形式加載 snappy lib,否則運(yùn)行時會報(bào)錯。

如果需要恢復(fù)的集合很多,本文的方法效率是很低的。

第五招:從文件里提取bson文檔來恢復(fù)

MongoDB json格式的文檔,最終是以BSON (Binary json)格式持久化存儲。

假設(shè)我們有個工具叫bsonextract(有興趣的同學(xué)可以嘗試實(shí)現(xiàn)下貢獻(xiàn)到社區(qū)里,直接調(diào) BSON 的接口,實(shí)現(xiàn)起來不難),它能從一個數(shù)據(jù)文件里分析并提取出所有 BSON 格式的內(nèi)容,那么我們也就達(dá)到了恢復(fù)數(shù)據(jù)的目的。

分析時,一段數(shù)據(jù)滿足2個條件,我們即可認(rèn)為是一個合法的 MongoDB 文檔

這段數(shù)據(jù)是一個合法的 BSON 文檔

包含一個id 字段 (oplog 集合不包含id 字段,但通常也沒有去恢復(fù) oplog 的必要)

上面這個方法不僅只能恢復(fù) wiredtiger 的數(shù)據(jù),對 MongoDB 所有存儲引擎都有效。

總結(jié)

?MongoDB 一直在優(yōu)化 MongoDB ,讓它能在 repair 模式里自動處理各種數(shù)據(jù)文件損壞(或部分丟失)的場景,目標(biāo)就是萬一遇到數(shù)據(jù)集損壞的場景,repair都能自動修復(fù)掉。

下面是 repair 以后能自動處理的一些場景及處理方法

Database files missing

An entry for a file will exist in the catalogue, but on disk file is gone

Will be impossible to recover from, remove the entry from the catalogue

Warn the user strongly about this (Error message)

Database files corrupted

An entry for a file will exist in the catalogue, but on disk file is unable to be opened

Attempt to rename the collection with WiredTiger to a new table that has some mention of it being corrupted in the name

Re-create the same collection with the same name (in order to continue repair)

Warn the user strongly about this problem, the creation of the new collection

Index files missing

An entry will exist in the catalogue, but on disk file is gone

Build the index as part of repair

Index files corrupted

An entry will exist in the catalogue, but on disk file is unable to be opened

Drop, then rebuild the index as part of repair

MongoDB catalogue metadata may be out of alignment with the WT files on disk

When something is missing on disk, then this should be resolved by the changes above

When something is missing from the catalogue metadata but exists as a wt table on disk we have no recourse. We would need a user accessible function to import

If the WiredTiger metadata is corrupt, then the database is corrupt

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容