1. 程式人生 > >【親測】教你如何搭建 MongoDB 復制集 + 選舉原理

【親測】教你如何搭建 MongoDB 復制集 + 選舉原理

解釋 端口 區別 init opera mem 技術 高可用 data

目錄

1·MongoDB 復制集概述
2·MongoDB 復制集部署
3·MongoDB 復制集管理(添加、移除等)
4·復制集的總結


MongoDB 復制集是什麽?

之前的一片文章講了 MongoDB 的安裝和日常的操作,有興趣的朋友可以看看 MongoDB 的安裝和簡單操作


1)什麽是復制集?

復制集是額外的一種數據副本,是跨多個服務器同步數據的過程,通俗的說就是可以在不同的服務器上備份數據,專業點說就是冗災處理。通過復制集可以對硬件和終端的服務進行恢復。


2)復制集的優勢如下:

  1-讓數據更加安全---(肯定啊,都是備份了,能不安全嗎!)
  2-數據的高可用性---(可以全年無休,7*24小時×××)
  3-災難恢復 ----(不用多說,既然是數據,能沒有恢復嗎)
  4-無停機維護---(比如說,備份、索引的重建等,MySQL 備份就需要鎖定 表 、或者行,而它不會)
  5-讀縮放----(額外的副本讀取)
  6-它對應用程序是透明的

3)復制集工作原理是什麽?

1·既然是一個功能性的東西,那麽存在肯定有它的工作原理和過程。MongoDB 的復制集至少需要兩個節點,是至少。其中一個是主節點 (Primary),這個主節點主要負責處理客戶端的請求,其他的都是從節點 (Secondary),負責復制主節點上的數據。


2·那麽我們常用的搭配方式有:一主一叢或一主多從,因為復制集的主從的選舉原理是從節點不允許選舉為當主節點,但是在實際的生產環境中,主服務器是不可能單點掛上去的,這樣要是主服務器掛掉了,那就涼涼。


3·客戶端主節點寫入數據,在從節點讀取數據,主節點與從節點進行數據交互保障數據的統一性。如果其中一個節點出現故障,其他節點馬上會把業務接過來而無需停機操作。


4·下圖是 MongoDB 復制集結構圖


技術分享圖片


它的特點如下:

N個節點的群集
任何節點可作為主節點
所有寫入都是在主節點,讀取是在從節點,實現讀寫分離
自動故障轉移
自動恢復


MongoDB 復制集部署

先介紹下環境:CenOS 7.4 上部署
部署前提:安裝 MongoDB ,了解什麽是實列、和創建多個實例
這裏安裝 MongoDB 就不再演示。我是直接 YUM 裝的。
需要了解 MongoDB 安裝 和 多實例的創建 請訪問:MongoDB 的安裝和命令
需要了解 MongoDB 與 MySQL 的區別 請訪問:MySQL - mmm 高可用集群
需要了解 MySQL 的讀寫分離 請訪問:MySQL 主從復制 + 讀寫分離


1)看多 MongoDB 的多實例創建的知道,創建實例前需要創建數據文件和日誌文件存儲路徑。

[root@localhost ~]# mkdir -p /data/mongodb/mongodb{2,3,4} ----(創建3個數據文件,因為自己 yum 安裝了一個,所以也算一個。)


[root@localhost ~]# mkdir -p /data/mongodb/logs ----(創建日誌文件路徑)
[root@localhost ~]# cd /data/mongodb/logs/
[root@localhost logs]# touch mongodb{2,3,4}.log -----(創建日誌文件夾)
[root@localhost logs]# chmod 777 *.log -----(給最大的權限)


2)修改主配置文件 ---- (需要註意的地方用加粗方式顯示)

[root@localhost ~]# vim /etc/mongod.conf ----(修改主配置文件)
修改內容如下:
#network interfaces
net:
> port: 27017 ----(默認端口號)
> bindIp: 0.0.0.0 # Listen to local interface only, comment to listen on all interfaces. ------------(修改監聽地址)

#security:

#operationProfiling:

> replication: -----------------(這裏需要去掉註釋)
> replSetName: kgcrs ------------(在這裏需要添加復制集的名字)


3)配置多實列 2 ,並且修改數據存儲路徑和日誌文件

[root@localhost ~]# cp -p /etc/mongod.conf /etc/mongod2.conf ----(把主配置文件復制一份)


[root@localhost ~]# vim /etc/mongod2.conf -----(修改實列的配置文件)
修改內容如下: ---(修改內容以加粗方式顯示)
systemLog:
destination: file
logAppend: true
> path: /data/mongodb/logs/mongod2.log ----(日誌文件的位子,這裏需要註意路徑,不能寫錯,之前創建的位置也不能有錯)

#Where and how to store data.
storage:
> dbPath: /data/mongodb/mongodb2 ----(數據存儲路徑,之前創建的路徑必須一樣)
journal:
enabled: true
#engine:
#mmapv1:
#wiredTiger:

#how the process runs
processManagement:
fork: true # fork and run in background
pidFilePath: /var/run/mongodb/mongod.pid # location of pidfile
timeZoneInfo: /usr/share/zoneinfo

#network interfaces
net:
> port: 27018 -----(端口號需要修改為不一樣的,自己能記住就行。)
bindIp: 0.0.0.0 # Listen to local interface only, comment to listen on all interfaces.

#security:

#operationProfiling:

> replication:
> replSetName: kgcrs ——(復制集的名稱都需要一致,名字可以自己修改)


4)配置多實例 3、4 (和上一步都是一樣,只是數據路徑,和日誌文件,還有端口號需要修改)

[root@localhost mongodb]# cp -p /etc/mongod2.conf /etc/mongod3.conf
[root@localhost mongodb]# cp -p /etc/mongod2.conf /etc/mongod4.conf
這裏就不再分別演示修改方式,會以一張圖來說明:修改數據路徑、日誌文件、端口號


下圖是多實例修改樣本:
技術分享圖片


5)當配置文件都 OK 後,就可以把4個實例全部啟動:

[root@localhost ~]# mongod -f /etc/mongod.conf ---(第一臺實例,是自己用YUM 裝的,可以看作一臺實例。)


[root@localhost ~]# mongod -f /etc/mongod2.conf ----(第二臺實例,需要註意,如果有報錯,很大一部分原因都是配置文件有問題,仔細檢查配置文件的路徑等問題)


[root@localhost ~]# mongod -f /etc/mongod3.conf ----(第三臺實例)


[root@localhost ~]# mongod -f /etc/mongod4.conf ----(第4臺實例)


6)進入第一臺實例,初始化復制集配置 ---(以上步驟只是創建實例,並不是復制集哦。)

[root@localhost ~]# mongo ---(因為第一臺的端口默認是 27017,所以這裏不用跟端口號,如果是其他實例就需要 加上 --port 27018)


> cfg={"_id":"kgcrs","members":[{"_id":0,"host":"192.168.198.128:27017"},{"_id":1,"host":"192.168.198.128:27018"},{"_id":2,"host":"192.168.198.128:27019"}]}

這裏需要說明此代碼:這裏包含了3個節點的復制集,格式不需要變,因為這裏是實驗環境,所以 IP 是相同的,在生產環境中,IP 地址是不一樣的。這裏只需要修改端口號就行,還有就是我們一共是4個實例,但是這裏只有3個,還剩下一個是為之後演示添加節點。


rs.initiate(cfg) ----(重新加載一下復制集,之後會有如下圖的解釋)


kgcrs:PRIMARY> rs.status() -----(查看復制集狀態)

"set" : "kgcrs",  ----(復制集名稱)
"date" : ISODate("2018-09-16T04:29:54.105Z"),
"myState" : 1,
"term" : NumberLong(1),
"syncingTo" : "",
"syncSourceHost" : "",
"syncSourceId" : -1,
"heartbeatIntervalMillis" : NumberLong(2000),
"optimes" : {
    "lastCommittedOpTime" : {
        "ts" : Timestamp(1537072188, 1),
        "t" : NumberLong(1)
    },
    "readConcernMajorityOpTime" : {
        "ts" : Timestamp(1537072188, 1),
        "t" : NumberLong(1)
    },
    "appliedOpTime" : {
        "ts" : Timestamp(1537072188, 1),
        "t" : NumberLong(1)
    },
    "durableOpTime" : {
        "ts" : Timestamp(1537072188, 1),
        "t" : NumberLong(1)
    }
},
"members" : [
    {
        "_id" : 0, 
        "name" : "192.168.198.128:27017",    -----(節點詳細信息)
        "health" : 1,  -----(健康值為 “1” 說明是在線狀態。“0” 為宕機狀態)
        "state" : 1,
        "stateStr" : "PRIMARY",  ------(主節點 PRIMARY)
        "uptime" : 848,
        "optime" : {
            "ts" : Timestamp(1537072188, 1),
            "t" : NumberLong(1)
        },
        "optimeDate" : ISODate("2018-09-16T04:29:48Z"),
        "syncingTo" : "",
        "syncSourceHost" : "",
        "syncSourceId" : -1,
        "infoMessage" : "could not find member to sync from",
        "electionTime" : Timestamp(1537072157, 1),
        "electionDate" : ISODate("2018-09-16T04:29:17Z"),
        "configVersion" : 1,
        "self" : true,
        "lastHeartbeatMessage" : ""
    },
    {
        "_id" : 1,
        "name" : "192.168.198.128:27018",------(第二臺節點)
        "health" : 1,
        "state" : 2,
        "stateStr" : "SECONDARY",  -----(**從節點SECONDARY )**
        "uptime" : 47,
        "optime" : {
            "ts" : Timestamp(1537072188, 1),
            "t" : NumberLong(1)
        },
        "optimeDurable" : {
            "ts" : Timestamp(1537072188, 1),
            "t" : NumberLong(1)
        },
        "optimeDate" : ISODate("2018-09-16T04:29:48Z"),
        "optimeDurableDate" : ISODate("2018-09-16T04:29:48Z"),
        "lastHeartbeat" : ISODate("2018-09-16T04:29:53.346Z"),
        "lastHeartbeatRecv" : ISODate("2018-09-16T04:29:53.725Z"),
        "pingMs" : NumberLong(0),
        "lastHeartbeatMessage" : "",
        "syncingTo" : "192.168.198.128:27017",
        "syncSourceHost" : "192.168.198.128:27017",
        "syncSourceId" : 0,
        "infoMessage" : "",
        "configVersion" : 1
    },
    {
        "_id" : 2,
        "name" : "192.168.198.128:27019",------(第三臺節點)
        "health" : 1,
        "state" : 2,
        "stateStr" : "SECONDARY", ------(從節點)
        "uptime" : 47,
        "optime" : {
            "ts" : Timestamp(1537072188, 1),
            "t" : NumberLong(1)
        },
        "optimeDurable" : {
            "ts" : Timestamp(1537072188, 1),
            "t" : NumberLong(1)
        },
        "optimeDate" : ISODate("2018-09-16T04:29:48Z"),
        "optimeDurableDate" : ISODate("2018-09-16T04:29:48Z"),
        "lastHeartbeat" : ISODate("2018-09-16T04:29:53.346Z"),
        "lastHeartbeatRecv" : ISODate("2018-09-16T04:29:53.725Z"),
        "pingMs" : NumberLong(0),
        "lastHeartbeatMessage" : "",
        "syncingTo" : "192.168.198.128:27017",
        "syncSourceHost" : "192.168.198.128:27017",
        "syncSourceId" : 0,
        "infoMessage" : "",
        "configVersion" : 1
    }
],
"ok" : 1,
"operationTime" : Timestamp(1537072188, 1),
"$clusterTime" : {
    "clusterTime" : Timestamp(1537072188, 1),
    "signature" : {
        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
        "keyId" : NumberLong(0)
    }
}

}


7)到此復制集創建完畢,但是我們還有一臺實例沒有添加到復制集中,所以現在演示復制集的添加:

kgcrs:PRIMARY> rs.add("192.168.198.128:27020") ----(添加一臺實列到復制集中)


{
"ok" : 1, ----(添加成功)
"operationTime" : Timestamp(1537072738, 2),
"$clusterTime" : {
"clusterTime" : Timestamp(1537072738, 2),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}


8)有添加,那麽就有移除,下面會演示移除的命令:

kgcrs:PRIMARY> rs.remove("192.168.198.128:27020")


{
"ok" : 1, -----(移除成功)
"operationTime" : Timestamp(1537072949, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1537072949, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}


9)到這裏實驗成功,那麽需要驗證它的功能性,下面會模擬故障轉移,在這裏是看不出實驗效果,只給方法。

[root@localhost ~]# ps aux | grep mongod ---(查看mongod的進程)
root 40778 0.6 6.4 1581996 64908 ? Sl 12:15 0:12 mongod -f /etc/mongod.conf
root 40822 0.6 6.1 1469704 61216 ? Sl 12:17 0:12 mongod -f /etc/mongod2.conf
root 40884 0.7 5.9 1504232 59000 ? Sl 12:18 0:11 mongod -f /etc/mongod3.conf
root 40912 0.5 5.3 1440660 53752 ? Sl 12:19 0:09 mongod -f /etc/mongod4.conf


[root@localhost ~]# kill -9 40778 ----(把進程 kill 掉 ,因為細心的朋友可以看到,40778 現在是主節點,把它 kill 掉,就是為了看其他節點會不會自動切換為主節點)


10)進入第二臺實列,查看復制集狀態

[root@localhost ~]# mongo --port 27018 ----(進入第二臺實例,這裏需要跟上端口)
kgcrs:SECONDARY> rs.status() ------(再次查看復制集狀態)


{
"set" : "kgcrs",
"date" : ISODate("2018-09-16T04:51:37.669Z"),
"myState" : 2,
"term" : NumberLong(2),
"syncingTo" : "192.168.198.128:27019",
"syncSourceHost" : "192.168.198.128:27019",
"syncSourceId" : 2,
"heartbeatIntervalMillis" : NumberLong(2000),
"optimes" : {
"lastCommittedOpTime" : {
"ts" : Timestamp(1537073492, 1),
"t" : NumberLong(2)
},
"readConcernMajorityOpTime" : {
"ts" : Timestamp(1537073492, 1),
"t" : NumberLong(2)
},
"appliedOpTime" : {
"ts" : Timestamp(1537073492, 1),
"t" : NumberLong(2)
},
"durableOpTime" : {
"ts" : Timestamp(1537073492, 1),
"t" : NumberLong(2)
}
},
"members" : [
{
"_id" : 0,
"name" : "192.168.198.128:27017", ----(第一臺節點)
"health" : 0, ----(原來的健康值變為 “0”)
"state" : 8,
"stateStr" : "(not reachable/healthy)",
"uptime" : 0,
"optime" : {
"ts" : Timestamp(0, 0),
"t" : NumberLong(-1)
},
"optimeDurable" : {
"ts" : Timestamp(0, 0),
"t" : NumberLong(-1)
},
"optimeDate" : ISODate("1970-01-01T00:00:00Z"),
"optimeDurableDate" : ISODate("1970-01-01T00:00:00Z"),
"lastHeartbeat" : ISODate("2018-09-16T04:51:36.332Z"),
"lastHeartbeatRecv" : ISODate("2018-09-16T04:47:29.932Z"),
"pingMs" : NumberLong(0),
"lastHeartbeatMessage" : "Connection refused",
"syncingTo" : "",
"syncSourceHost" : "",
"syncSourceId" : -1,
"infoMessage" : "",
"configVersion" : -1
},
{
"_id" : 1, ----(第二臺實例)
"name" : "192.168.198.128:27018",
"health" : 1, ----(健康值為 “1”
"state" : 2,
"stateStr" : "SECONDARY", ----(節點狀態是:從幾從節點)
"uptime" : 2060,
"optime" : {
"ts" : Timestamp(1537073492, 1),
"t" : NumberLong(2)
},
"optimeDate" : ISODate("2018-09-16T04:51:32Z"),
"syncingTo" : "192.168.198.128:27019",
"syncSourceHost" : "192.168.198.128:27019",
"syncSourceId" : 2,
"infoMessage" : "",
"configVersion" : 3,
"self" : true,
"lastHeartbeatMessage" : ""
},
{
"_id" : 2, -----(第三臺節點)
"name" : "192.168.198.128:27019",
"health" : 1, -----(健康值為 ‘1’)
"state" : 1,
"stateStr" : "PRIMARY", -----(現在是第三臺節點為主節點)
"uptime" : 1349,
"optime" : {
"ts" : Timestamp(1537073492, 1),
"t" : NumberLong(2)
},
"optimeDurable" : {
"ts" : Timestamp(1537073492, 1),
"t" : NumberLong(2)
},
"optimeDate" : ISODate("2018-09-16T04:51:32Z"),
"optimeDurableDate" : ISODate("2018-09-16T04:51:32Z"),
"lastHeartbeat" : ISODate("2018-09-16T04:51:36.289Z"),
"lastHeartbeatRecv" : ISODate("2018-09-16T04:51:37.431Z"),
"pingMs" : NumberLong(0),
"lastHeartbeatMessage" : "",
"syncingTo" : "",
"syncSourceHost" : "",
"syncSourceId" : -1,
"infoMessage" : "",
"electionTime" : Timestamp(1537073261, 1),
"electionDate" : ISODate("2018-09-16T04:47:41Z"),
"configVersion" : 3
}
],
"ok" : 1,
"operationTime" : Timestamp(1537073492, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1537073492, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}


11)從以上數據可以看出,當主節點掛掉後,從節點會自動切換為主節點,但是又不是按照順序來推薦誰當主節點,這裏的推薦的原理,後面會講到。當然,這裏是自動切換主從,我們也可以手動進行切換

[root@localhost ~]# mongod -f /etc/mongod.conf ----(把上個步驟停止的實例啟動起來,方便我們實驗)
[root@localhost ~]# mongo --port 27019 ----(進入主節點服務器,因為我們需要來進行手動切換主從。)


kgcrs:PRIMARY> rs.freeze(30) ----(暫停30秒不參加選舉)
kgcrs:PRIMARY> rs.stepDown(60,30) ----(讓主節點交出位子,維持從節點狀態不少於60秒,同時等待30秒使主節點和從節點日誌同步)
kgcrs:SECONDARY> rs.status() ----(再次查看復制集狀態)


12)在從節點默認的情況下,我們是無法在從節點上讀取數據的,只有執行以下命令:

kgcrs:SECONDARY> rs.slaveOk() ----(執行此命令才可以在從節點上讀取數據,否則是不允許讀取)


總結:

1·復制集信息要點說明:health 為 “1” 代表健康,“0” 代表宕機。state 為 “1” 代表主節點,為 “2” 代表從節點


2·在配置實例時需要特別註意修改的數據存儲路徑,日誌存儲位子,端口號的修改。


3·復制集最少需要兩個節點,這裏主節點復制處理客戶端請求,從節點復制主節點上的數據


4·它可以實現群集的高可用,當故障時會自動切換,管理員也可以手動切換。


5·在復制集初始化配置時要保證從節點上沒有數據。


6·在初始化完復制集參數後,需要通過命令 :rs.initate(cfg) 命令啟動復制集。

【親測】教你如何搭建 MongoDB 復制集 + 選舉原理