備份有許多種方法。但無論采用哪種方法,備份操作都會增加系統的負擔:備份通常需将所有資料讀取到記憶體中。是以,通常情況下,應對副本集的非主節點(與主節點相對)進行備份,或在空閑時段對獨立伺服器進行備份。
如非特殊聲明,本節中的所有技術均适用于任何mongod程式,無論是獨立伺服器還是副本內建員。
生成檔案系統快照(snapshot)是最簡單的備份方法。然而,該方法的實作需要兩點條件,即檔案系統本身支援快照技術,以及在運作mongod時必須開啟日記系統 (journaling)。如系統滿足這兩點條件,則該方法無需其他準備,隻需生成快照即可,時間不限。
在恢複時,確定mongod沒有在運作。從快照恢複資料的确切指令取決于不同的檔案系統,不過基本上就是恢複快照,然後啟動mongod即可。如果是對正在運作的系統生成快照,那麼快照中的資料内容本質上相當于使用kill -9指令強制終止mongod後的資料内容。是以,mongod在啟動時會對日志(journal)檔案進行重放(replay),然後開始正常運作。
另一種備份方式是複制資料目錄中的所有檔案。沒有檔案系統的支援,我們就無法同時複制所有檔案,是以在進行備份時必須防止資料檔案發生改變。可使用fsynclock指令做到這一點:
該指令鎖定(lock)資料庫,禁止任何寫入,并進行同步(fsync),即将所有髒頁重新整理至磁盤,以確定資料目錄中的檔案是最新的,且不會被更改。
一旦運作了這一指令,mongod會将之後的所有寫入操作加入隊列等待,且在解鎖前不會對這些寫入操作進行處理。注意,這一指令會停止所有資料庫的寫入操作,而不隻是已連接配接的那個資料庫。
當fsynclock指令傳回指令行後,複制資料目錄中的所有檔案到備份位置。在Linux中,可使用以下指令等:
確定複制了資料目錄中的每一個檔案和檔案夾到備份位置。漏掉檔案或檔案夾可能會損壞備份或使其不再可用。
資料複制完成後,解鎖資料庫,使其能夠再次進行寫入操作:
資料庫即開始正常處理寫入操作。
注意:身份驗證和fsynclock指令存在一些鎖定問題。如果啟用了身份驗證,則在調用fsyncLock()和fsyncUnlock()期間不要關閉shell。如果在這期間斷開了連接配接,則可能無法進行重新連接配接,并不得不重新開機mongod。fsyncLock()的設定在重新開機後不會保持生效,mongod總是以非鎖定模式啟動。
除使用fsynclock外,還可關閉mongod,複制檔案,然後重新開機mongod。關閉mongod會将所有更改立即重新整理到磁盤,防止備份期間出現新的寫入操作。
若要恢複資料目錄備份,請保證mongod沒有在運作,且所有待恢複的資料目錄為空。将備份的資料檔案複制到資料目錄,然後啟動mongod。例如,下列指令會使用前面提及的指令恢複備份檔案:
忽略那些有關複制部分資料目錄的警告資訊。隻要知道要複制哪些檔案,即可使用這種方式備份單獨的資料庫。例如,要備份名為myDB的資料庫,隻需複制所有名為myDB.*的檔案,包括字尾名為.ns的檔案。如使用了--directoryperdb選項,隻需複制該資料庫對應的整個資料目錄。
可複制資料庫對應的檔案到資料目錄,完成指定資料庫的恢複。如需進行這種部分恢複,應確定資料庫上一次是正常關閉的。如遇到崩潰或突然停機,不要嘗試恢複一個單獨的資料庫,而應用備份檔案替換整個資料目錄,然後啟動mongod,進而允許日記檔案進行重放。
提示:不要同時使用fsyncLock和mongodump。資料庫被鎖定也許會使得mongodump永遠處于挂起狀态,這取決于資料庫正在進行的其他操作。
最後一種備份方式是使用mongodump。之是以最後提到它,是因為mongodump有些許缺點。它備份和恢複的速度較慢,在處理副本集時存在一些問題。然而它也存在以下優點:當想備份單獨的資料庫、集合甚至集合中的子集時mongodump是個很好的選擇。
運作mongodump --help,可看到mongodump具有很多選項。此處我們重點關注那些與備份相關的實用選項。
要備份所有資料庫,隻需運作mongodump即可。如果在同一台機器上運作mongod和mongodump,隻需指定mongod運作時占用的端口即可:
mongodump會在目前目錄建立一個轉儲(dump)目錄,其中包含了一份所有資料的傾卸。轉儲目錄中的目錄和子目錄由資料庫和集合構成。真正的資料存放在擴充名為.bson的檔案裡,其中以BSON格式依次存儲了集合中的所有文檔。可使用MongoDB自帶的bsondump工具檢視.bson檔案。
使用mongodump時甚至無需伺服器處于運作狀态:可使用--dbpath選項來指定資料目錄,mongodump會使用指定的資料檔案進行備份。
如果mongod正在運作,則不應使用--dbpath選項。
mongodump存在一個問題,即它并非進行快照備份,也就是說在備份的過程中,系統可能會繼續進行寫入操作。于是可能出現,開始備份時mongodump先對資料庫A進行轉儲,随後在mongodump正在對資料庫B進行轉儲的同時,删除了資料庫A。然而mongodump已經對資料庫A進行了轉儲,于是最終轉儲得到的結果,是一個在原伺服器上并不存在的資料快照。
為避免這種情況的發生,如果運作mongod時使用了--replSet選項,則可使用mongodump的--oplog選項。這會将轉儲過程中伺服器進行的所有操作記錄下來,這樣在恢複備份時就會重新執行這些操作。這樣就可以得到源伺服器上某一時間點的資料快照。
如果給mongodump—個副本集的連接配接字串(例如,setName/seed1,seed2,seed3),如果備份節點存在的話,它會自動選擇一個備份節點進行轉儲。
恢複mongodump産生的備份,可使用mongorestore工具:
如果轉儲資料庫時使用了--oplog參數,運作mongorestore時必須使用--oplogReplay選項,以得到某一時間點的快照。
如果在運作的伺服器上進行資料替換,可使用--drop選項,以在恢複一個集合前先删除它。當然此選項并非必選項。
随着版本的變化,mongodump和mongorestore指令的具體作用和用法發生了改變。為避免相容性問題,應盡量使用同版本的mongodump和mongorestore。可運作mongodump --version 和 mongorestore --version來檢視各自的版本。
1.使用mongodump和mongorestore來轉移集合和資料庫
可從轉儲中恢複完全不同的資料庫和集合。當在不同環境中使用不同的資料庫名稱 (例如,dev和prod),但集合的名稱相同時,這一特性會很實用。
将一個擴充名為.bson的檔案恢複為特定的資料庫和集合,隻需在指令行中指定恢 複目标:
2.管理唯一索引帶來的混亂
在任何集合中,如果存在除_id以外的其他唯一索引(unique index),則應考慮使用mongodump和mongorestore以外的備份方式。具體地說,唯一索引要求複制期間資料不發生可能破壞其唯一索引限制的改變。最安全的方法是先想辦法“當機” 資料,然後使用前兩節中提到的方法來進行備份。
如果決定使用mongodump和mongorestore進行備份,那麼在恢複備份時,可能需要對資料進行一定的預處理。
通常,應該對備份節點進行備份:這會為主節點減輕負擔,也可以在不影響應用的情況下鎖定備份節點(隻要應用不向備份節點發送讀取請求)。可使用之前提到過的三種方式中的任意一種,對副本集中的成員進行備份,但推薦使用檔案系統快照或複制資料檔案的方式。這兩種方式在應用于副本集備份節點時無需做任何修改。
副本集啟用後,使用mongodump進行備份就不那麼簡單了。首先,如果使用mongodump,則必須在備份時使用--oplog選項,來得到一個基于某時間點的快照;否則備份的狀态不會和任何其他叢集成員的狀态相吻合。在恢複時也必須建立一份oplog,否則被恢複的成員就不知道應該同步到哪裡。
要從mongodump生成的備份中,對副本內建員進行恢複,可将該成員作為一個單獨的伺服器啟動,此時要使用一個空的資料目錄。首先,像上一節中提到過的那樣,使用--oplogReplay選項運作mongorestore。現在它應該包含了一份完整的資料副本,但還需要一份oplog。運作createColAection指令來建立oplog:
以位元組為機關指定集合大小。
現在需要填充oplog。最簡單的方式是用備份中的oplog.bson檔案來填充local.oplog.rs集合:
注意:這并不是對于oplog的轉儲檔案(dump/local/oplog.rs.bson),而是進行轉儲期 間發生的操作。一旦mongorestore完成,即可将伺服器作為副本內建員重新啟動。
不可能對正在運作的分片叢集進行“完美地”備份,因為無法及時得到叢集在某一時間點完整狀态的快照。然而,通常情況下都會避開該限制,因為随着叢集的增大,從備份中恢複整個叢集的可能性越來越小。是以,在面對分片叢集時,我們更關注分塊的備份,即單獨備份配置伺服器和副本集。
在對分片叢集進行備份和恢複操作之前,應先關閉均衡器。這是因為在過于混亂的環境中是無法得到一份前後一緻的快照的。
當叢集很小或正在進行開發時,我們可能想要轉儲和恢複整個叢集。要達到這一目的,應先關閉均衡器,然後通過mongos運作mongodump。這會在mongodump所運作的機器上建立所有分片的備份。
要恢複此種備份,需運作mongorestore并連接配接到一個mongos。
關閉均衡器後,可使用檔案系統快照或複制資料目錄的方式,備份配置伺服器和毎一個分片。然而不可避免的是,我們不可能在完全相同的時刻得到這些備份,這可能造成問題。另外,在打開均衡器時會進行資料合并,在分片中備份的某些資料可能會由此消失。
更多時候,隻需恢複叢集中的某個單獨分片。如果不是很挑剔的話,可使用剛剛在前面提到過的單獨伺服器處理方法進行分片的備份恢複。
有一個問題要着重注意:假設在星期一對叢集進行了備份。到了星期四,磁盤發生損壞,我們不得不恢複備份。然而,在這幾天裡,新的資料塊可能移動到了這一分片上。而周一進行的分片備份中并不包含這些新增的資料塊。也許我們能夠使用配置伺服器的備份,找到這些消失了的資料塊在星期一時的位置,但這比隻是恢複分片要困難得多。在大多數情況下,恢複分片,忽略那些消失的資料塊,是更好的選擇。
可直接連接配接到一個分片上來恢複備份,而不需要通過mongos。
以上提及的備份方式,即使和上一次備份時相比,隻發生了很小的更改,也都必須對所有資料進行一次完整的複制。如果資料和寫入量有很大的關系,那麼我們可能希望了解一下增量備份。
與每天或每周進行一次完整的資料複制不同,我們隻需進行一次備份,然後使用oplog來備份這之後的所有操作。這種技術比之前提及的技術都要複雜,是以除非确實需要,否則應盡量選擇其他技術。
這一技術需要兩台運作mongod的機器,即機器A和機器B。A是主機器(可能是副本集中的備份節點),B則用來進行備份:
(1) 記錄下A的oplog中最近一次的操作時間(optime):
把該數值記錄在安全的地方--等下會用到它。
(2) 對資料進行備份,使用以上提及的任何一種方式,得到一份基于某時間點的備份。恢複備份至B上的資料目錄。
(3) 定期添加A上的操作至B,進而完成資料的複制。MongoDB的發行版中自帶了一個特殊的工具mongooplog(讀作mon-goop-log),将這一操作變得簡單。mongooplog從一台伺服器的oplog中複制資料,并将其中的操作應用在另一台伺服器的資料集上。在B上運作:
其中--seconds選項後跟的參數,應為第一步中計算出的start變量和目前時間的內插補點,再額外加上幾秒(重複地重放操作也好過資料丢失)。
這使得備份更接近最新的資料。這種技術有些像是手動地同步一個備份節點,是以我們也許隻是想在備份節點上使用延時複制以代替增量備份。
作者:小家電維修
相見有時,後會無期。