最牛MongoDB災難恢復(WiredTiger.wt文件損壞,Mongo沒法啓動)

WiredTiger.wt文件是mongoDB的元數據文件,存儲了其餘數據庫表的元數據信息。筆者最近遇到了WiredTiger.wt文件損壞的狀況,MongoDB沒法啓動,數據庫中的重要數據千鈞一髮...css

 

1、網上大多數文章的恢復方案 - 使用wt工具對數據進行打撈

因爲筆者以前沒有接觸過MongoDB,對其知之甚少,只能參考網上的文章來試圖恢復數據。看了下網上的文章,大可能是說經過wt工具來打撈數據。然而wt工具打撈數據,須要WiredTiger.wt文件是無缺可用,並不適用於筆者遇到的情形。node

2、源碼面前,了無祕密 - 讀源碼,直接從wt數據文件恢復數據

網上的恢復方案不對症,無奈只能另尋他法。數據庫

經過閱讀wiredtiger的代碼發現,wt數據文件中,數據庫記錄以bson格式存儲的,並默認經過snappy進行了壓縮,數據默認沒有進行加密vim

1. wt數據文件結構分析

使用vim的十六進制模式觀察collection*.wt數據文件發現:ruby

  • wt數據文件的前4096字節是該wt文件的元數據信息
  • wt數據文件從4096開始存儲數據庫記錄
  • wt數據文件的記錄對齊4096

把視線聚焦到單獨的某個記錄上:app

0001000: 0000 0000 0000 0000 0100 0000 0000 0000 ................ 0001010: 70e2 0000 0200 0000 0705 0000 0060 0000 p............`.. 0001020: fa49 5207 0100 0000 0581 80e2 c1c2 42e2 .IR...........B. 0001030: 0000 105f 6964 0057 0000 0010 7573 6572 ..._id.W....user 0001040: 9454 0000 0000 0000 b0c4 0330 5f69 6400 .T.........0_id. 0001050: e6a2 675c 1074 6173 6b01 0df0 4402 0000 ..g\.task...D... 0001060: 0002 696d 6167 655f 6e61 6d65 002f 0000 ..image_name./.. 0001070: 006c 796d 7068 5f6e 6f64 655f 6d69 6372 .lymph_node_micr 0001080: 6f73 636f 7065 5753 495f 3139 3032 3238 oscopeWSI_190228 0001090: 5f31 3930 3330 3839 3231 312e 7376 7300 _1903089211.svs. 00010a0: 1069 053f e869 6400 7f09 0000 026a 736f .i.?.id......jso 

在wiredtiger源碼中定義每一個數據數記錄的存儲格式:工具

  • 00 - 07 字節,recno,記錄編號,關係不大
  • 00 - 15 字節,write_generation
  • 16 - 19 字節,記錄解壓後的size(記錄默認是經過snappy壓縮的),用於解壓
  • 28 - 31 字節,在源碼沒找到,可是經過觀察,應該是該記錄的存儲size,對齊4096,用於記錄讀取
2. 記錄讀取及snappy解壓

從記錄頭部讀取頭部64字節的數據,從而解析到:加密

  • 記錄解壓後size,後文稱 decompress_size
  • 記錄存儲size,後文稱 store_size

從記錄開頭讀取 store_size 字節的數據,跳過WT_BLOCK_COMPRESS_SKIP字節,對其後數據進行snappy解壓,解壓後數據總大小應爲 decompress_size 。spa

3. 從記錄中提取bson格式的數據

記錄解壓後,前面的不少字節並非bson的數據,筆者也沒詳細去看前面的字節究竟是什麼,而是經過一個巧辦法暴力地提取了bson格式的數據。code

bson格式的前4個字節是bson數據的size,後面的數據會以 類型、名稱、值這樣的形式存儲,具體可參考網上關於bson格式解釋的文章

0001000: 0000 0000 0000 0000 0100 0000 0000 0000  ................
0001010: 70e2 0000 0200 0000 0705 0000 0060 0000 p............`.. 0001020: fa49 5207 0100 0000 0581 80e2 c1c2 42e2 .IR...........B. 0001030: 0000 105f 6964 0057 0000 0010 7573 6572 ..._id.W....user 

數據庫記錄中有個 _id 這樣的字段、該字段的類型爲32位數值,在bson中該類型表示爲 0x10,所以這個32位數值類型的_id,會存儲爲105f 6964。其中,10是類型,5f 6964是_id,其後的32位存儲了它的實際數值。
因爲_id是bson數據中的第一個字段,根據bson格式定義,105f 6964前面的4個字節 42e2 0000是bson數據的大小,也就是bson數據的起始位置。

經過該尋找105f 6964,能夠定位到bson數據的起始位置,並將bson數據存儲成bson文件,如xxx.bson

4. 使用bsondump來解析bson文件,獲得數據
[root@h-100 ~]# bsondump xxx.bson 

3、切記、切記

使用MongoDB時,像WiredTiger.wt這樣重要並不大的文件,多作備份,避免沒必要要的麻煩

5、關注筆者

專一筆者公衆號,閱讀更多幹貨文章:)

相關文章
相關標籤/搜索