mongodb中提供了復制(Replication)機制,通過該機制可以幫助我們很容易實現讀寫分離方案,並支持災難恢復(服務器斷電)等意外情況下的數據安全。
在老版本(1.6)中,Mongo提供了兩種方式的復制:master-slave及replica pair模式(注:mongodb最新支持的replset復制集方式可看成是pair的升級版,它解決pair只能在兩個結點間同步的限制,支持多個結點同步且支持主從宕機時的自動切換, 在1.6版以後提供)。
利用前者,我們可以實現讀寫分離(主從復制模式),後者則支持當主服務器斷電情況下的集群中其它slave自動接管,並升級為主服務器。 並且如果後來的也出錯了,那麼master狀態將會轉回給第一個服務器(之前宕機但後來又恢復運行的服務器)。
同時mongodb支持使用安全認證(enable)。不管哪種replicate方式,只要在master/slave中創建一個能為各個database認識的用戶名/密碼即可。其認證過程如下:
slave先在local.system.users裡查找一個名為"repl"的用戶,找到後用它去認證master。如果"repl"用戶沒有找到,則使用local.system.users中的第一個用戶去認證。local數據庫和admin數據庫一樣,local中的用戶可以訪問整個db server。
下面介紹分別介紹一下這兩種復制的配置方式:
Master-Slave(主從)模式:
一個server可以同時為master和slave。一個slave可以有多個master(不推薦,可能會產生不可預期的結果)。
配置選項:
--master 以主服務器方式啟動
--slave 以從服務器方式啟動
--autoresync:自動重新sync,因為該操作會copy 主服務器上的所有document,比較耗時,在10分鐘內最多只會進行一次。
--oplogSize:指定master上用於存放更改的數據量,如果不指定,在32位機上最少為50M,在64位機上最少為 1G,最大為磁盤空間的5%。
--source 主服務器地址(與--slave組合使用)
--only 僅限於同步指定數據庫(下面示例為test庫)
--slavedelay 同步延時
下面是本人在本地為了測試方便所使用的配置參數
Master: IP->10.0.1.103
mongod --dbpath=d:mongodbdb --master --oplogSize 64
Slave: IP->10.0.4.210
mongod --dbpath=d:mongodbdb --slave --source 10.0.1.103:27017 --only test --slavedelay 100
補充:受限的master-master復制,這種模式對插入、查詢及根據_id進行的刪除操作都是安全的。但對同一對象的並發更新無法進行。Mongo 不支持完全的master-master復制,通常情況下不推薦使用master-master模式,但在一些特定的情況下master-master也可用。master-master也只支持最終一致性。配置master-master只需運行mongod時同時加上--master選項和 --slave選項。如下:
mongod --dbpath=d:mongodbdb --port 27017 --master --slave --source localhost:27018
mongod --dbpath=d:mongodbdb --port 27018 --master --slave --source localhost:27017
Replica pairs模式
以這種方式啟動後,數據庫會自動協商誰是master誰是slave。一旦一個數據庫服務器斷電,另一個會自動接管,並從那一刻起起為master。萬一另一個將來也出錯了,那麼master狀態將會轉回給第一個服務器。以這種復制方式啟動mongod的命令如下:
配置選項:
mongod --pairwith <remoteserver> --arbiter <arbiterserver>
--pairwith: remoteserver是pair裡的另一個server
--arbiter: arbiterserver是一個起仲裁作用的Mongo數據庫,用來協商pair中哪一個是master。arbiter運行在第三個機器上,利用“平分決勝制”決定在pair中的兩台機器不能聯系上對方時讓哪一個做master,一般是能同arbiter通話的那台機器做master。如果不加--arbiter選項,出現網絡問題時兩台機器都作為master。
注:可使用db.$cmd.findOne({ismaster:1})可以檢查當前哪一個database是master。
另外這種模式下的兩台機器只能滿足最終一致性。當replica pair中的一台機器完全掛掉時,需要用一台新的來代替。如(n1, n2)中的n2掛掉,這時用n3來代替n2。步驟如下:
1. 告訴n1用n3來代替n2:db.$cmd.findOne({replacepeer:1});
2. 重啟n1讓它同n3對話:mongod --pairwith n3 --arbiter <arbiterserver>
3. 啟動n3:mongod --pairwith n1 --arbiter <arbiterserver>。
在n3的數據沒有同步到n1前n3還不能做master,這個過程長短由數據量的多少決定。
了解了復制模式之後,還有一個問題需要介紹一下,不是就是本文中mongodb使用cap collection來存儲操作日志,並進而使用日志來復制(同步)結點間的數據,其中由主結點保存的操作的記錄叫做oplog(operation log的簡稱)。
Oplog存在一個叫local的特殊數據庫中,在oplog.$main集合。Oplog中的每一個文檔表示一個在主結點上執行的操作。文檔主要包括4塊內容,如下:
Ts:操作的時間戳。時間戳類型是一個用來跟蹤操作是何時執行的一種內部類型。它由4字節的時間戳和四字節的增量計數器組成。
Op:執行的操作的類型,大小為1字節。(例如,“i”代表insert,"u":update, "d":delete, "n":none無操作等)
Ns:執行操作的命名空間(集合名)
O:執行操作的文檔。對於插入,這是將要插入的文檔。
另外這種日志只保存會“改變數據庫狀態”的操作。查詢操作不會記錄在oplog中。
好了,了解這些知識之後,我們就來開始看一下如何調試master-slave模式的源碼,首先要在vs2010中打開mongod項目,並將啟動參數中設置如下:
--master --oplogSize 64 (master IP為10.0.1.103)
如下圖:
之後編譯該項目,啟動該主服務結點,如下:
接著我們可以在本地或另外一台機器上啟動一個slave結點:
mongod --dbpath=d:mongodbdb --slave --source 10.0.1.103:27017 --only test --slavedelay 100
下面介紹一下master(主服務端)的代碼執行流程。首先我們打開instance.cpp文件,找到下面方法:
//instance.cpp
// Returns false when request includes end
void assembleResponse( Message &m, DbResponse &dbresponse, const SockAddr &client ) {
......
if ( op == dbQuery ) {
if ( handlePossibleShardedMessage( m , &dbresponse ) )
return;
receivedQuery(c , dbresponse, m );
}
//服務端(master) 收到message執行相關查詢操作
else if ( op == dbGetMore ) {
if ( ! receivedGetMore(dbresponse, m, currentOp) )
log = true;
}
.....
}
&