mongoDB研究筆記:複製集資料同步機制

郭遠威發表於2013-08-31

   http://www.cnblogs.com/guoyuanwei/p/3279572.html  概述了複製集,整體上對複製集有了個概念,但是複製集最重要的功能之一資料同步是如何實現的?帶著這個問題,下面展開分析。

先利用mongo客戶端登入到複製集的primary節點上。

>mongo --port 40000

檢視例項上所有資料庫

rs0:PRIMARY> show dbs

local   0.09375GB

可以看到只有一個local資料庫,因為此時還沒有在複製集上建立任何其它資料庫,local資料庫為複製集所有成員節點上預設建立的一個資料庫。在primary節點上檢視local資料上的集合:

rs0:PRIMARY> show collections

oplog.rs

slaves

startup_log

system.indexes

system.replset

如果是在secondary節點則local資料庫上的集合與上面有點不同,secondary節點上沒有slaves集合,因為這個集合儲存的是需要從primary節點同步資料的secondary節點;secondary節點上會有一個me集合,儲存了例項本身所在的伺服器名稱;secondary節點上還有一個minvalid集合,用於儲存對資料庫的最新操作的時間截。其它集合primary節點和secondary節點都有,其中startup_log集合表示的是mongod例項每一次的啟動資訊;system.indexes集合儲存的是當前資料庫(local)上的所有索引資訊;system.replset集合儲存的是複製集的成員配置資訊,複製集上的命令rs.conf()實際上是從這個集合取的資料返回的。最後要介紹的集合是oplog.rs,這個可是重中之中。

mongoDB就是通過oplog.rs來實現複製集間資料同步的,為了分析資料的變化,先在複製集上的primary節點上建立一個資料庫students,然後插入一條記錄。

rs0:PRIMARY> use students

switched to db students

rs0:PRIMARY> db.scores.insert({"stuid":1,"subject":"math","score":99});

接著檢視一下primary節點上oplog.rs集合的內容:

rs0:PRIMARY> use local

switched to db local

rs0:PRIMARY> db.oplog.rs.find();

返回記錄中會多出一條下面這樣的記錄(裡面還有幾條記錄是複製集初始化時建立的):

{ "ts" : { "t" : 1376838296, "i" : 1 }, "h" : NumberLong("6357586994520331181"),

 "v" : 2, "op" : "i", "ns" : "students.scores", "o" : { "_id" : ObjectId("5210e2

98d7b419b44afa58cc"), "stuid" : 1, "subject" : "math", "score" : 99 } }

裡面有幾個重要欄位,其中"ts"表示是這條記錄的時間截,"t"是秒數,"i"每秒操作的次數;欄位"op"表示的是操作碼,值為"i"表示的是insert操作;"ns"表示插入操作發生的名稱空間,這裡值為: "students.scores",由資料庫和集合名構成;"o"表示的是此插入操作包含的文件物件;

當primary節點完成插入操作後,secondary節點為了保證資料的同步也會完成一些動作:

所有secondary節點檢查自己的local資料上oplog.rs集合,找出最近的一條記錄的時間截;接著它會查詢primary節點上的oplog.rs集合,找出所有大於此時間截的記錄;最後它將這些找到的記錄插入到自己的oplog.rs集合中並執行這些記錄所代表的操作;通過這三步策略,就能保證secondary節點上的資料與primary節點上的資料同步了。

檢視一下secondary節點上的資料,證明上面的分析是正確的。

rs0:SECONDARY> show dbs

local   0.09375GB

students        0.0625GB

  在secondary節點上新插入了一個資料庫students。但是有一點要注意:現在還不能在secondary節點上直接查詢students集合上的內容,預設情況下mongoDB的所有讀寫操作都是在primary節點上完成的,後面也會介紹通過設定從secondary節點上來讀,這將引入一個新的主題,後面再分析。

關於oplog.rs集合還有一個很重要的方面,那就是它的大小是固定的,mongoDB這樣設定也是有道理的,假如大小沒限制,那麼隨著時間的推移,在資料庫上的操作會逐漸累積,oplog.rs集合中儲存的記錄也會逐漸增多,這樣會消耗大量的儲存空間,同時對於某個時間點以前的操作記錄,早已同步到secondary節點上,也沒有必要一直儲存這些記錄,因此mongoDB將oplog.rs集合設定成一個capped型別的集合,實際上就是一個迴圈使用的緩衝區。

固定大小的oplog.rs會帶來新的問題,考慮下面這種場景:假如一個secondary節點因為當機,長時間不能恢復,而此時大量的寫操作發生在primary節點上,當secondary節點恢復時,利用自己oplog.rs集合上最新的時間截去查詢primary節點上的oplog.rs集合,會出現找不到任何記錄。因為長時間不線上,primary節點上的oplog.rs集合中的記錄早已全部重新整理了一遍,這樣就不得不手動重新同步資料了。因此oplog.rs的大小是很重要,在32位的系統上預設大小是50MB,在64位的機器上預設是5%的空閒磁碟空間大小,也可以在mongod啟動命令中通過項—oplogSize設定其大小。

相關文章