mongoDB研究筆記:復制集故障轉移機制


上面的介紹的數據同步(http://www.cnblogs.com/guoyuanwei/p/3293668.html)相當於傳統數據庫中的備份策略,mongoDB在此基礎還有自動故障轉移的功能。在復制集概述那一節提到過心跳"lastHeartbeat"字段,mongoDB就是靠它來實現自動故障轉移的。 mongod實例每隔2秒就向其它成員發送一個心跳包以及通過rs.staus()中返回的成員的”health”值來判斷成員的狀態。如果出現復制集中primary節點不可用了,那么復制集中所有secondary的節點就會觸發一次選舉操作,選出一個新的primary節點。如上所配置的復制集中如果primary節點宕機了,那么就會選舉secondary節點成為primary節點,arbiter節點只是參與選舉其它成員成為primary節點,自己永遠不會成為primary節點。如果secondary節點有多個則會選擇擁有最新時間截的oplog記錄或較高權限的節點成為primary節點。oplog記錄在前面復制集概述中已經描述過,關於復制集中節點權限配置的問題可在復制集啟動的時候進行設置,也可以在啟動后重新配置,這里先略過這一點,集中精力討論故障轉移。

如果是某個secondary節點失敗了,只要復制集中還有其它secondary節點或arbiter節點存在,就不會發生重新選舉primary節點的過程。

下面模擬兩種失敗場景:一是secondary節點的失敗,然后過一段時間后重啟(時間不能無限期,否則會導致oplog.rs集合嚴重滯后的問題,需要手動才能同步);二是primary節點失敗,故障轉移發生。

先分析第一種情況的測試,當前復制集的配置情況如下:

(1)rs0:PRIMARY> rs.conf()

{

"_id" : "rs0",

"version" : 3,

"members" : [

{

"_id" : 0,

"host" : "Guo:40000" //primary節點

},

{

"_id" : 1,

"host" : "Guo:40001" //secondary節點

},

{

"_id" : 2,

"host" : "Guo:40002", //arbiter節點

"arbiterOnly" : true

}

]

}

(2)通過Kill掉secondary節點所在的mongod實例,通過rs.status()命令查看復制集狀態,secondary節點狀態信息如下:

"_id" : 1,

"name" : "Guo:40001",

"health" : 0,

"state" : 8, //表示成員已經down機

"stateStr" : "(not reachable/healthy)",

"uptime" : 0,

"optime" : {

"t" : 1376838296,

"i" : 1

},

"optimeDate" : ISODate("2013-08-18T15:04:56Z")

(3)接着通過primary節點插入一條記錄:

rs0:PRIMARY> db.scores.insert({stuid:2,subject:"english",score:100})

(4)再次查看復制集狀態信息rs.status(),可以看到primary成員節點上oplpog信息如下:

"optime" : {

"t" : 1376922730,

"i" : 1

},

"optimeDate" : ISODate("2013-08-19T14:32:10Z"),

與上面down機的成員節點比較,optime已經不一樣,primary節點上要新於down機的節點。

(5)重新啟動Kill掉的節點

>mongod --config E:\mongodb-win32-i386-2.4.3\configs_rs0\rs0_1.conf

查詢復制集狀態信息rs.status(),觀看節點"Guo:40001"的狀態信息如下:

"_id" : 1,

"name" : "GUO:40001",

"health" : 1,

"state" : 2,

"stateStr" : "SECONDARY",

"uptime" : 136,

"optime" : {

"t" : 1376922730, //與上面primary節點一致了

"i" : 1

},

"optimeDate" : ISODate("2013-08-19T14:32:10Z"),

說明secondary節點已經恢復,並且從primary節點同步到了最新的操作數據。進一步通過查詢secondary節點上local數據庫上的oplog.rs集合來進行驗證,發現多了一條下面這樣的記錄:

{ "ts" : { "t" : 1376922730, "i" : 1 }, "h" : NumberLong("-451684574732211704"),

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

6a99c5a3ae472a6900"), "stuid" : 2, "subject" : "english", "score" : 100 } }

這正是在primary節點上插入的記錄,再次證明數據確實同步過來了。

接下來測試第二種情況:

(1)將primary節點Kill掉。

查詢復制集的狀態信息rs.status()

"name" : "Guo:40000",

"health" : 0,

"state" : 8,

"stateStr" : "(not reachable/healthy)"

字段"health"的值為0,說明原來的primary節點已經down機了。

"name" : "Guo:40001",

"health" : 1,

"state" : 1,

"stateStr" : "PRIMARY"

字段"stateStr"值為"PRIMARY",說明原來secondary節點變成了primary節點。

(2)在新的primary節點上插入一條記錄

rs0:PRIMARY> db.scores.insert({stuid:3,subject:"computer",score:99})

(3)重新恢復"Guo:40000"節點(原來的primary節點)

>mongod --config E:\mongodb-win32-i386-2.4.3\configs_rs0\rs0_0.conf

再次查看復制集狀態rs.status()

"name" : "Guo:40000",

"health" : 1,

"state" : 2,

"stateStr" : "SECONDARY",

"uptime" : 33,

"optime" : {

"t" : 1376924110,

"i" : 1

},

當"Guo:40000"實例被重新激活后,變成了secondary節點,oplog也被同步成最新的了。說明當primary節點故障時,復制集能自動轉移故障,將其中一個secondary節點變為primary節點,讀寫操作繼續在新的primary節點上進行。原來primary節點恢復后,在復制集中變成了secondary節點。

上面兩中情況都得到了驗證,但是有一點要注意,mongDB默認情況下只能在primary節點上進行讀寫操作。對於客戶端應用程序來說,對復制集的讀寫操作是透明的,默認情況它總是在primary節點上進行。 mongoDB提供了很多種常見編程語言的驅動程序,驅動程序位於應用程序與mongod實例之間,應用程發起與復制集的連接,驅動程序自動選擇primary節點。當primary節點失效,復制集發生故障轉移時,復制集將先關閉與所有客戶端的socket連接,驅動程序將返回一個異常,應用程序收到這個異常,這個時候需要應用程序開發人員去處理這些異常,同時驅動程序會嘗試重新與primary節點建立連接(這個動作對應用程序來說是透明的)。假如這個時候正在發生一個讀操作,在異常處理中你可以重新發起讀數據命令,因為讀操作不會改變數據庫的數據;假如這個時候發生的是寫操作,情況就變得微妙起來,如果是非安全模式下的寫,就會產生不確定因素,寫是否成功不確定,如果是安全模式,驅動程序會通過getlasterror命令知道哪些寫操作成功了,哪些失敗,驅動程序會返回失敗的信息給應用程序,針對這個異常信息,應用程序可以決定怎樣處置這個寫操作,可以重新執行寫操作,也可以直接給用戶暴出這個錯誤。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM