自我學習,僅供參考:
資料庫總是會遇到各種失敗的場景,如網路連線斷開、斷電等,儘管journaling日誌功能也提供了資料恢復的功能,但journaling通常是針對單個節點來說的,只能保證單節點資料的一致性,而複製集通常是由多個節點組成,每個節點除了journaling日誌恢復功能外,整個複製集還具有故障自動轉移的功能,這樣能保證資料庫的高可用性。在生產環境中一個複製集最少應該包含三個節點,其中有一個必須是主節點,典型的部署結構如下圖:
其中每個節點都是一個mongod程式對應的例項,節點之間互相週期性的通過心跳檢查對方的狀態,預設情況下primary節點負責資料的讀、寫,second節點備份primary節點上的資料(如何備份?下面會分析),但是arbiter節點不會從primary節點同步資料,從它的名字arbiter可以看出,它起到的作用只是當primary節點故障時,能夠參與到複製集剩下的節點中,選擇出一個新的primary節點,它自己永遠不會變為primary節點,也不會參與資料的讀寫。也就是說,資料庫的資料會存在primary和second節點中,second節點相當於一個備份,當然second節點可以有多個,當primary節點故障時,second節點有可能變為primary節點。上圖是一個生產環境所需的最少節點數,下面就配置一個這樣的複製集。
(1)建立複製集中每個節點存放資料的目錄
E:\mongodb-win32-i386-2.4.3\db_rs0\data\rs0_0
E:\mongodb-win32-i386-2.4.3\db_rs0\data\rs0_1
E:\mongodb-win32-i386-2.4.3\db_rs0\data\rs0_2
(2)建立複製集中每個節點的日誌檔案
E:\mongodb-win32-i386-2.4.3\db_rs0\logs\rs0_0.log
E:\mongodb-win32-i386-2.4.3\db_rs0\logs\rs0_1.log
E:\mongodb-win32-i386-2.4.3\db_rs0\logs\rs0_2.log
(3)為複製集中的每個節點建立啟動時所需的配置檔案
第一個節點配置檔案為:E:\mongodb-win32-i386-2.4.3\configs_rs0\rs0_0.conf 內容如下:
dbpath = E:\mongodb-win32-i386-2.4.3\db_rs0\data\rs0_0
logpath = E:\mongodb-win32-i386-2.4.3\db_rs0\logs\rs0_0.log
journal = true
port = 40000
replSet = rs0
其中dbpath指向資料庫資料檔案存放的路徑(在第一步中已建立好),logpath指向資料庫的日誌檔案路徑(第二步中已建立好),journal表示對於此mongod例項是否啟動日誌功能,port為例項監聽的埠號,rs0為例項所在的複製集名稱,更多引數的意思可以參考mongoDB手冊。
第二個節點配置檔案為:E:\mongodb-win32-i386-2.4.3\configs_rs0\rs0_1.conf 內容如下:
dbpath = E:\mongodb-win32-i386-2.4.3\db_rs0\data\rs0_1
logpath = E:\mongodb-win32-i386-2.4.3\db_rs0\logs\rs0_1.log
journal = true
port = 40001
replSet = rs0
第三個節點配置檔案為:E:\mongodb-win32-i386-2.4.3\configs_rs0\rs0_2.conf 內容如下:
dbpath = E:\mongodb-win32-i386-2.4.3\db_rs0\data\rs0_2
logpath = E:\mongodb-win32-i386-2.4.3\db_rs0\logs\rs0_2.log
journal = true
port = 40002
replSet = rs0
(4)啟動上面三個節點對應的mongoDB例項
mongod –config E:\mongodb-win32-i386-2.4.3\configs_rs0\rs0_0.conf
mongod –config E:\mongodb-win32-i386-2.4.3\configs_rs0\rs0_1.conf
mongod –config E:\mongodb-win32-i386-2.4.3\configs_rs0\rs0_2.conf
觀察一下每個例項的啟動日誌,日誌中都有如下內容:
[rsStart] replSet can't get local.system.replset config from self or any seed (EMPTYCONFIG)
[rsStart] replSet info you may need to run replSetInitiate -- rs.initiate() in the shell -- if that is not already done
上面日誌說明雖然已經成功啟動了三個例項,但是複製集還沒配置好,複製集的資訊會儲存在每個mongod例項上的local資料庫中即local.system.replset上。按照上圖所描述那樣,你應該通過配置確定哪個節點為primary、哪個為second、哪個為arbiter。下面開始配置複製集。
(5)啟動一個mongo客戶端,連線到上面的一個mongod例項
>mongo --port 40000
執行以下命令初始化複製集
> rs.initiate()
{
"info2" : "no configuration explicitly specified -- making one",
"me" : "Guo:40000",
"info" : "Config now saved locally. Should come online in about a min e.",
"ok" : 1
}
這個時候的複製集還只有剛才這個初始化的成員,通過如下命令檢視到。
> rs.conf()
{
"_id" : "rs0",
"version" : 1,
"members" : [
{
"_id" : 0,
"host" : "Guo:40000"
}
]
}
按照mongoDB的預設設定,剛才執行初始化命令的這個mongod例項將成為複製集中的primary節點。
(6)接下來在複製集中新增上圖中的second節點和arbiter節點,繼續在上面那個mongod例項上執行如下命令:
rs0:PRIMARY> rs.add("Guo:40001")
{ "ok" : 1 }
rs0:PRIMARY> rs.addArb("Guo:40002")
{ "ok" : 1 }
注意此時命令的字首變為了:rs0:PRIMARY,說明當前執行命令的機器是複製集中primary機器,上面的命令通過rs.add()新增一個預設的second節點,rs.addArb()新增一個預設的arbiter節點。命令成功執行後,就會生成上圖所示那樣的一個複製集。
(7)觀察整個複製集的狀態資訊,幾個重要引數會在後面說明。
rs0:PRIMARY> rs.status()
{
"set" : "rs0",//複製集的名稱
"date" : ISODate("2013-08-18T09:03:49Z"),
"myState" : 1, //當前節點成員在複製集中的位置,如1表示primary,2表示secondry
"members" : [//複製集的所有成員資訊
{
"_id" : 0, //成員編號
"name" : "Guo:40000",//成員所在的伺服器名稱
"health" : 1,//成員在複製集中是否執行,1表示執行,0失敗
"state" : 1,//成員在複製集中的狀態,1是primary
"stateStr" : "PRIMARY",//成員在複製集中的狀態名稱
"uptime" : 2186,//成員的線上時間,單位是秒
"optime" : {//這個是用來進行同步用的,後面重點分析
"t" : 1376816431,
"i" : 1
},
"optimeDate" : ISODate("2013-08-18T09:00:31Z"),
"self" : true //成員為當前命令所在的伺服器
},
{
"_id" : 1,
"name" : "Guo:40001",
"health" : 1, ,//成員在複製集中是否執行,1表示執行
"state" : 2 ,//成員在複製集中的狀態,2是secondary
"stateStr" : "SECONDARY",
"uptime" : 306,
"optime" : {
"t" : 1376816431,
"i" : 1
},
"optimeDate" : ISODate("2013-08-18T09:00:31Z"),
"lastHeartbeat" : ISODate("2013-08-18T09:03:47Z"),
"lastHeartbeatRecv" : ISODate("2013-08-18T09:03:47Z"),
"pingMs" : 0,//此遠端成員到本例項間一個路由包的來回時間
"syncingTo" : "Guo:40000"//此成員需要從哪個例項同步資料
},
{
"_id" : 2,
"name" : "Guo:40002",
"health" : 1,
"state" : 7, //成員在複製集中的狀態位置,7是arbiter
"stateStr" : "ARBITER",
"uptime" : 198,
"lastHeartbeat" : ISODate("2013-08-18T09:03:49Z"),
"lastHeartbeatRecv" : ISODate("1970-01-01T00:00:00Z"),
"pingMs" : 0,//此遠端成員到本例項間一個路由包的來回時間
}
],
"ok" : 1
}
上面複製集狀態資訊的輸出是基於primary例項的,也可以再secondary例項上輸出複製集的狀態資訊,包含的欄位與上面大致相同。上面的輸出有些地方還需進一步解釋,如在arbiter成員節點上,沒有欄位syncingTo,說明他不需要從primary節點上同步資料,因為它只是一個當主節點發生故障時,在複製集中剩下的secondary節點中選擇一個新的priamry節點的仲裁者,因此執行此例項的機器不需要太多的儲存空間。
上面輸出的欄位中還有幾個時間相關的欄位如:"date"表示當前例項所在伺服器的時間,"lastHeartbeat"表示當前例項到此遠端成員最近一次成功傳送與接收心跳包的時間,通過比較這個兩個時間可以判斷當前例項與此成員相差的時間間隔,比如某個成員當機了,本例項發像此當機成員的心跳包就不會被成功接收,隨著時間推移,本例項的data欄位值與此成員上的lastHeartbeat差值就會逐漸增加。
上面還有一個optime欄位,這個欄位的值說明了本例項最近一次更改資料庫的時間"t" : 1376816431以及每秒執行的運算元據庫的次數"i" : 1,此欄位的值實際上是從本例項上的local資料庫中的oplog.rs集合上讀取的,這個集合還詳細記錄了具體是什麼操作,如插入語句、修改語句等。複製集中的每一個例項都會有一個這樣的資料庫和集合,如果複製集執行正常,理論上來說,每一個mongod例項上此集合中的記錄應該相同。實際上mongoDB也是根據此集合來實現複製集中primary節點與secondary節點間的資料同步。