前幾日在VPS折騰MongoDB,由於機器內存實在是太小了(1G,又跑了別的程序),進行重建索引操作時,內存不足被系統給kill了。強制kill的Mongo無法在repair
模式下恢復,只能直接用Wiredtiger工具讀取二進制數據文件進行恢復了。
准備
官方文檔對於這種情況並沒有給予更多的提示了,這個時候只能拿出強大的Google了(百度已經拯救不了)。
經過一番資料查找,得出以下結論:
- 在
repair
模式失敗的情況下,恢復MongoDB是比較困難了 - MongoDB的數據使用WiredTiger引擎進行存儲,可以直接使用相關工具讀取二進制文件數據
- 網上有一篇成功恢復數據的文章可以參考 Link
按照資料,首先要找到你需要恢復的Collection所對應的wt
文件,它們一般在Mongo安裝目錄的data
文件夾下面,文件的格式應該類似這樣
collection-0--282010455938071573.wt
然后把數據文件和data
下面其他一些存有必要信息的文件一起復制到一個新的目錄mongo-bak
(為啥不在原來目錄操作?又失敗了怎么辦),如下:
collection-0--282010455938071573.wt _mdb_catalog.wt sizeStorer.wt storage.bson WiredTiger WiredTiger.basecfg WiredTiger.lock WiredTiger.turtle WiredTiger.wt
數據准備就緒,我們需要一個工具 wt utility,
wget http://source.wiredtiger.com/releases/wiredtiger-3.0.0.tar.bz2 tar xvf wiredtiger-3.0.0.tar.bz2 cd wiredtiger-3.0.0 sudo yum install snappy-devel -y ./configure --enable-snappy make
注意:我的系統是CentOS,如果你是Ubuntu的話,要把上面命令中的sudo yum install snappy-devel -y
換成sudo apt-get install libsnappy-dev build-essential
snappy是必須要安裝的插件,不然無法正常解碼二進制數據問題(就算你使用zlib模式進行壓縮,還是需要它)
打撈數據
裝好工具后,執行
./wt -v -h ../mongo-bak -C "extensions=[./ext/compressors/snappy/.libs/libwiredtiger_snappy.so]" -R salvage collection-14--4826876641079835696.wt
其中../mongo-bak
是我們剛剛放恢復文件的目錄,把損壞的data文件拷貝到../mongo-bak這里面,全部考進來,collection-0--282010455938071573.wt
就是需要恢復的wt文件
順利的話,可以看到這樣的信息 /mnt/mongodb/data 是mongodb里的data 文件的路徑
WT_SESSION.salvage 77982300
里面的數字應該是可以恢復的記錄,有時候你會發現這個數字比預想的要大,原因是mongo把刪除操作也會緩存在內存中,意外關閉時來不及寫入磁盤,導致數據量增多。
另外,剛剛那個操作會重寫wt文件里面的內容,所以盡量不要用源文件進行操作。修復好的wt文件並不能被mongo直接使用,我們需要使用wt工具里面的dump命令把里面的數據進行導出, 輸入以下命令:
./wt -v -h ../mongo-bak -C "extensions=[./ext/compressors/snappy/.libs/libwiredtiger_snappy.so]" -R dump -f ../collection.dump collection-0--282010455938071573
這個命令會跑比較長的時間,可以用另一個命令行窗口查看collection.dump
文件的生成情況,值得注意的事,根據集合內容的不同,dump文件的大小也有比較大的差異,我的一個3G大小zlib模式的wt文件,輸出的dump有27G大小,一定要准備充足的磁盤空間,另外內存大概也會占用和wt文件近似的大小。
重建數據
原來的Mongo已經不可用了,我們需要一個新的Mongo來承載恢復出來的數據,首先在新的Mongo中建立一個collection
use cloud db.historydatas.insert({test: 1}) db.historydatas.remove({}) db.historydatas.stats()
這里在cloud數據庫下建立了historydatas集合,stats命令為了查看這個集合對應的wt文件,在輸出的信息里,能找到這樣一行
"uri" : "statistics:table:collection-7895--1435676552983097781"
其中的collection-7895--1435676552983097781
就是wt文件的名字了
先把新的mongo停了,我們需要直接對數據文件進行操作
./wt -v -h /mnt/mongodb/data -C "extensions=[./ext/compressors/snappy/.libs/libwiredtiger_snappy.so]" -R load -f ../collection.dump -r collection-5--9115211387822471702
這里的/mnt/mongodb/data是新mongo的存放數據文件的地址,wt工具會把dump直接寫入對應的集合文件里,完成后會看到
table:collection-7895--1435676552983097781: 77982300
好了,我們再次啟動mongo
root> show dbs historydatas → 3.087GB local → 0.000GB root> use anydb switched to db historydatas historydatas> show collections back → 0.000GB / 3.087GB historydatas> db.back.count() 0
詭異的事情出現了,數據庫大小看起來是沒有問題的,但查不到記錄總數
historydatas> db.back.find({}, {_id: 1}) { "_id": ObjectId("55e07f3b2e967329c888ac74") } { "_id": ObjectId("55e07f3b2e967329c888ac76") } ... { "_id": ObjectId("55e07f402e967329c888ac85") } Fetched 20 record(s) in 29ms -- More[true]
可見數據已經寫入了,但數據庫的狀態還是有點問題的,我們直接執行
db.repairDatabase()
進行修復,然后就可以正常查看記錄總數了
historydatas> db.back.count() 7789230
太好了,現在數據恢復了,但里面的內容肯定有不同程度的缺失,需要進一步的處理。
其他
根據網上的資料,本文中的操作僅對 >=3.2版本的mongo有效。
正確mongo流程可以按照官網提示,使用 --repair
命令進入修復模式,mongo會對所有數據進行一次掃描,並且重建索引,等到修復完畢就可以正常啟動了。
但這個操作是有一個前提的,那就是文件數據必須要完整。問題是我的Mongo是被強制kill的,文件數據難免已經混亂,所以每次修復程序在重建索引這一步都會報錯。
***wiredtiger 項目github地址,一定要選擇對應的mongodb版本下載***
https://github.com/wiredtiger/wiredtiger