讀古今文學網 > MongoDB實戰 > 10.3 維護 >

10.3 維護

本節我會介紹三個最常用的MongoDB維護任務,首先要討論的是備份。和其他數據庫一樣,你也該有個日常備份策略。隨後,我會介紹壓緊(compaction),因為在少數幾種情況下,數據文件需要壓緊。最後再簡要地說一下升級,在條件允許時,你會希望運行最新的穩定版MongoDB。

10.3.1 備份與恢復

在運行生產環境數據庫時,有一部分工作內容就是準備應對災難,備份在其中扮演了重要的角色。當災難不期而至時,好的備份能力挽狂瀾,這時你絕不會為日常備份所投入的時間和精力而感到後悔。但還是有些用戶決定不做備份,當他們遇到問題無法恢復自己的數據庫時,只能說是自作自受,你可千萬別向他們學習。

MongoDB數據庫有兩個常規的備份策略,第一個是使用mongodumpmongorestore工具;第二,而且很可能是更常用的,是複製原始的數據文件。

1. mongodumpmongorestore

mongodump能把數據庫的內容導出成BSON文件,而mongorestore則能讀取並還原這些文件。這些工具在備份單個集合、數據庫乃至整個服務器時都非常有用。它們能運行於線上服務器(無需鎖定或關閉服務器),你也可以在服務器被鎖定或關閉時將它們指向一組數據文件。最簡單的mongodump運行方法如下:

$ mongodump -h localhost --port 27017
  

這能把localhost服務器上的每個數據庫和集合都導出到名為dump的目錄裡。導出的內容包含每個集合裡的所有文檔,還包含定義了用戶和索引的系統集合。但值得注意的是索引本身並不包含其中,也就是說,在恢復時必須重建全部索引。如果你的數據集特別大,或是擁有大量索引,那麼這會花費不少時間。

在還原BSON文件時,運行mongorestore,將它指向dump文件夾:

$ mongorestore -h localhost --port 27017 dump
  

請注意,在還原過程中mongorestore默認不會刪除數據。因此,如果你向一個現有數據庫還原數據,請務必帶上--drop標誌。

2. 基於數據文件的備份

大多數用戶選擇基於文件的備份,將原始數據文件複製到一個新的位置。這種方法在大多數情況下比mongodump要快,因為在備份和還原時無需轉換數據。3唯一潛在的問題是基於文件的備份要求鎖定數據庫,但是通常你都會鎖定從節點,因此在備份的過程中應用程序應該能夠保持在線。

3. 舉個例子,採用這種策略會保留全部的索引——無需在還原時重建索引。

複製數據文件

用戶經常會犯錯誤,沒有先鎖定數據庫就去複製數據文件或製作快照。在禁用Journaling日誌時,這會造成數據文件損壞。在開啟Journaling日誌時,製作快照沒問題,但複製數據文件有點麻煩,容易發生狀況。

因此,無論是否開啟了Journaling日誌,本書建議總是在複製數據文件或製作磁盤快照前鎖定數據庫。比起鎖定數據庫所帶來的安寧和對文件完整性的保障,由此引發的輕微延時是值得的。

複製數據文件,先要確認它們都處於一致狀態,為此可以關閉數據庫或是鎖定它。由於關閉數據庫在一些部署情況下太麻煩了,所以大多數用戶都選擇進行鎖定。以下是用來同步並鎖定數據庫的命令:

> use admin
> db.runCommand({fsync: 1, lock: true})
  

此時,數據庫是寫鎖定的,數據文件都同步到了磁盤上,也就是說可以安全地複製數據文件了。如果正運行在一個支持快照的文件系統或存儲系統上,最好先製作一個快照,以後再做複製,這能讓你快點解鎖。

如果無法製作快照,就必須在複製數據文件時讓數據庫保持在鎖定狀態。如果是從一個從節點複製數據文件,請確保該節點仍連著主節點,並有足夠的oplog讓它在備份期間保持離線狀態。

一旦完成快照或者備份,就可以解鎖數據庫了。看似神秘的解鎖命令是這樣的:

> db.$cmd.sys.unlock.findOne
> { \"ok\" : 1, \"info\" : \"unlock requested\" }
  

請注意,這僅僅是請求解鎖,數據庫可能不會立刻解鎖,可以運行db.currentOp方法驗證數據庫是否已經解鎖。

10.3.2 壓緊與修復

MongoDB包含了修復數據庫的功能,可以通過命令行觸發修復服務器上的所有數據庫:

$ mongod --repair
  

也可以運行repairDatabase命令修復單個數據庫:

> use cloud-docs
> db.runCommand({repairDatabase: 1})
  

修復是個離線操作,在執行時,數據庫的讀寫都將被鎖定。修復就是讀取和重寫所有數據文件並重建各個索引,在此過程中丟棄掉損壞的文檔。也就是說要修復數據庫,需要有足夠的空餘磁盤空間來存儲重寫的數據。要說修復的開銷很大,那還是輕的,修復大型數據庫能花好幾天。

MongoDB的修復最初是用作恢復受損數據庫的最後一道防線。在未正常關閉,又沒有開啟Journaling日誌時,修復是讓數據文件回到一致狀態的唯一途徑。幸運的是,如果部署時使用了複製,至少有一台機器開啟了Journaling日誌,並且進行日常線下備份,你應該永遠也用不上執行修復的恢復功能。依靠修復來進行恢復是種愚蠢的做法,應盡量避免這麼做。

那麼數據庫修復又有什麼好處呢?運行修復能壓緊數據文件並重建索引。自v2.0版本起,MongoDB對數據文件壓緊並沒有太好的支持,因此如果執行了很多隨機刪除,尤其是刪除小文檔(小於4 KB),那麼總存儲大小可能仍然保持不變甚至是繼續增長。壓緊數據文件能有效應對此類對空間的過度使用。

要是沒有時間或資源執行完整的修復,還有兩個選擇,它們都是針對單個集合進行操作的:可以重建索引或是壓緊集合。要重建索引,可以使用reIndex方法:

> use cloud-docs
> db.spreadsheets.reIndex
  

這招很管用,但一般而言,索引空間是能高效重用的;數據文件空間才是問題。所以compact命令通常是更好的選擇。compact會重寫數據文件,並重建集合的全部索引。下面展示如何在Shell中運行compact命令:

> db.runCommand({ compact: \"spreadsheets\" })
  

該命令的初衷是在運行中的從節點上壓緊,以此避免停機時間。一旦完成副本集中所有從節點的壓緊,可以降級主節點,再對它進行壓緊。如果必須在主節點上運行compact命令,可以向命令鍵中添加{force: true}。請注意,如果選擇這種方式,該命令會對系統進行寫鎖定:

> db.runCommand({ compact: \"spreadsheets\", force: true })
  

10.3.3 升級

MongoDB還是一個相對比較「年輕」的項目,這意味著它的新版本中一般都包含很多重要的補丁和性能改進。出於這些原因,你應該盡可能運行最新的穩定版本。至少到v2.0為止,升級的過程就是簡單地關閉老的mongod進程,用老的數據文件啟動新的mongod進程。MongoDB的後續版本可能會對索引和數據文件格式做些小的改變,這可能會讓升級過程稍微煩瑣一點。請查看最新的發佈說明以瞭解正確的推薦做法。

當然,在升級MongoDB時,可能會要升級副本集集群,這種情況下,常規的策略是一次升級一個節點,先從從節點開始。