1. 程式人生 > >學習MongoDB--(9-4):複製(副本集)

學習MongoDB--(9-4):複製(副本集)

先說一下副本集的概念:有自動故障恢復功能的主從結構!前面講到的主從結構和副本集最大的區別就是:副本集沒有固定的“主節點”,整個叢集結構會動態選舉出一個“主節點”,當其不能工作了,則會動態變更到其他節點。副本集對其節點又特殊的稱呼:活躍節點(“主節點”)和 備份節點(“從節點”)。

副本集最美妙的地方是其自動化,在當前活躍節點因故障停止時,備份節點會自動升級為活躍節點!以維持系統的正常執行。

搭建副本集的過程為:我們首先需要為副本集起一個名稱(試驗名稱為“yy”),然後使用選項--replSet來啟動副本集的第一個服務:

C:\Documents and Settings\liuxjd>mongod --dbpath e:\mdbserver1 --port 10000 --lo
gpath e:\mdblog1\log.log --replSet yy/localhost:10001
all output going to: e:\mdblog1\log.log
上述我們通過--replSet yy/localhost:10001(這裡有一點尤為注意:副本集名稱yy後的分隔符必須為“/”,否則後面註冊後失敗!),這是指定了該副本集yy中的另外一個MongoDB服務,其監聽的埠為本機的10001,但此時我們還並未啟動該服務!

我們看一下第一個節點日誌此時的輸出包含如下語句:

Sun Sep 02 10:48:51 [rsStart] replSet can't get local.system.replset config from self or any seed (EMPTYCONFIG)
Sun Sep 02 10:48:51 [rsStart] replSet info you may need to run replSetInitiate -- rs.initiate() in the shell -- if that is not already done

我們開始啟動副本集的第二個服務:

C:\Documents and Settings\liuxjd>mongod --dbpath e:\mdbserver2 --port 10001 --lo
gpath e:\mdblog2\log.log --replSet yy/localhost:10000
all output going to: e:\mdblog2\log.log
我們還可以啟動副本集的第三臺服務,下面兩種方式均可:
C:\Documents and Settings\liuxjd>mongod --dbpath e:\mdbserver3 --port 10002 --lo
gpath e:\mdblog3\log.log --replSet yy/localhost:10000
all output going to: e:\mdblog3\log.log

C:\Documents and Settings\liuxjd>mongod --dbpath e:\mdbserver3 --port 10002 --lo
gpath e:\mdblog3\log.log --replSet yy/localhost:10000,localhost:10001
all output going to: e:\mdblog3\log.log
即在啟動第三臺服務時,可以只指定副本集中的一個服務,或同時指定。副本集的一個特性為:自動檢測,你僅指定單臺伺服器後,MongoDB會自動搜尋並連線到同一副本集的其餘的節點。
從第一臺服務的啟動日誌中,我們看到,集合中local.system.replset中沒有任何配置資訊,並且副本集還需要在shell中執行replSetInitiate命令來進行初始化。我們通過其中任意一臺伺服器(試驗中我們使用的第二臺)執行命令初始化(注意該命令需要在admin資料庫下執行),該集合中會自動插入配置資訊,並且配置資訊會在副本集內各個伺服器間被複制:
C:\Documents and Settings\liuxjd>mongo localhost:10001
MongoDB shell version: 2.0.7
connecting to: localhost:10001/test
> use admin
switched to db admin
> db.runCommand({"replSetInitiate" : {
... "_id" : "yy",
... "members" : [
...     {
...         "_id" :1,
...         "host": "localhost:10000"
...     },
...     {
...         "_id" : 2,
...         "host" : "localhost:10001"
...     },
...     {
...         "_id" : 3,
...         "host" : "localhost:10002"
...     }
... ]}});
{
        "info" : "Config now saved locally.  Should come online in about a minut
e.",
        "ok" : 1
}
>
執行這個命令的文件稍顯複雜,我們解釋一下各個鍵的含義:

1》 “_id” : “yy”, 這個鍵指明瞭副本集的名稱

2》 “members” :[...], 這個鍵指明伺服器列表,我們以後還可以往副本集中加入伺服器

3》 “_id” : N, 內嵌文件的鍵,用於唯一標示副本集中的某一臺伺服器

4》 “host”:host address, 指明伺服器的主機和埠號 

通過命令初始化完畢後,我們檢視日誌:

Sun Sep 02 10:52:11 [rsHealthPoll] replSet member localhost:10001 is now in state PRIMARY
Sun Sep 02 10:52:25 [rsHealthPoll] replSet member localhost:10000 is now in state SECONDARY
Sun Sep 02 10:52:17 [rsHealthPoll] replSet member localhost:10002 is now in state SECONDARY

第二個伺服器成為了活躍節點,其餘兩個伺服器均是備份節點。備份節點會抽取活躍節點的oplog,來維持和活躍節點的資料同步!備份節點無法直接通過客戶端進行些操作,查詢操作也要指明“slaveok”(在shell進行查詢,主從結構的從節點可以通過shell客戶端查詢資料,而副本集控制嚴一些,其備份節點通過shell客戶端也無法直接查詢,提示需要設定slaveok選項,但shell查詢好像沒有提供這種支援!

初始化會將副本集的資訊儲存在副本集各個節點的資料庫local的集合system.replset中,我們到第一臺伺服器上檢視一下該集合:

SECONDARY> use local;
switched to db local
SECONDARY> db.system.replset.find();
{ "_id" : "yy", "version" : 1, "members" : [    {       "_id" : 1,      "host" :
 "localhost:10000" },   {       "_id" : 2,      "host" : "localhost:10001" },
{       "_id" : 3,      "host" : "localhost:10002" } ] }
SECONDARY>
執行初始化命令時,鍵“members”的內嵌文件中,還有如下兩個鍵可以使用:

1》 priority :N,優先順序,指明一個伺服器的優先順序,預設為1,可以是[0,1000],通過這個我們可以指明副本集某臺伺服器節點初始為活躍節點

2》 arbiterOnly :true,仲裁節點,特定指明某個伺服器節點為仲裁節點,仲裁節點不會複製資料,不會成為活躍節點,其存在的目的只有一個:當前活躍節點失效後,副本集內重新投票選活躍節點時,防止出現僵局!

【故障切換】

噹噹前活躍節點失效,包括兩種情況:

1》 當前活躍節點宕機或本身異常

2》 當前活躍節點會通過心跳跟蹤叢集中多收節點對其可見,如果數量小於叢集伺服器數量的一半,會自動降級為備份節點

此時,叢集會投票選舉出一個新的活躍節點(新比較優先順序,優先順序相同的,各個節點判斷哪個資料最新,就會投哪個),任何時候,活躍節點的資料會被認為是最新的。當重新確定了活躍節點後,所有其他節點都要重新進行完整同步!