安裝MongoDB 3.4 for CentOS 7
vi /etc/yum.repos.d/mongodb.repo
mongodb-org-3.4]
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/3.4/x86_64/
gpgcheck=1
enabled=1
gpgkey=https://www.mongodb.org/static/pgp/server-3.4.asc
然後在執行
yum install -y mongodb-org
另外,需要將selinux(/etc/selinux/config)設定為SELINUX=Passive或Disable,詳細可參考:
https://docs.mongodb.com/manual/tutorial/install-mongodb-on-red-hat/
MongoDB Replica Set介紹
MongoDB 算是一個很發展非常成熟的專案,大多數的系統裝起 MongoDB 應該都不會有太大的困難,今天介紹一下進階一點點的用法,Replica Set。資料庫系統做高可用 Replication (副本) 模式算是很常見的架構,在大陸稱為「主備模式」主要提供一份資料庫即時映射的副本,好讓主要的服務資料庫發生異常時可以接手工作。同時,另一個優勢就是可以進行資料備援,或者用來進行查詢。此外,當資料庫大到一定的程度,傳統的 dump 工具將很難完成任務,備援的方法就可以靠 Replication 來完成。
現在的 Open Source 系統發展得很快,官方提供的版本就早已經支援 Replication,想想以前的 PostgreSQL 在 5.x 的時候還要自己 Patch 第三方 Project 進行編譯,比起來真的省事多了。
官方有提供三種 Replica Set 架構 (Pattern),如下:
- Three Member Replica Sets
- Replica Sets with Four or More Members
- Geographically Distributed Replica Sets
第一種 Three Member Replica Sets 是最常用的架構,由三個 MongoDB 節點組成,每個節點其實都是 Mongod 服務。第二種由更多的節點組成,備援能力更強,但我沒有研究,無從介紹。最後一種 Distributed Replica Sets 主要滿足異地備援的需求,這個聽起來不錯。
今天來介紹 MongoDB 最典型的副本架構,主要由三個節點構成,如下:
正常情況對 Primary 節點進行讀寫,資料會自動複製 (Replication) 到另外兩組 Secondary 節點,這些節點彼此透過 Heartbeat (每隔一段時間試探節點是否存活的方式) 檢測狀態,正常的情況每 2 秒會送出 Heartbeat,若是超過 10 秒沒有回覆,那就是 GG 了。如下:
當主要連線的節點發生故障時,會選出一台 Secondary 成為 Primary 接手工作,這樣的能力稱為 Automatic Failover,如下:
安裝與設定MongoDB Replica Set
大概知道工作原理以後,那麼我們來看看如何設定 Replica Set 架構。
開始之前我們先在 /etc/hosts 定義這三台要安裝的 hostname 與 IP Address,當然如果您想透過 DNS 服務來管理也是可以的。
vi /etc/hosts
10.21.1.45 mongsh1
10.21.1.46 mongsh2
10.21.1.44 mongsh3
建立一個讓 Replica Set 專用的全新資料庫目錄
mkdir -p /home/mongod
chown -R mongodb:mongodb /home/mongod
三台伺服器皆需要做此設定,以方便確認資料庫的目錄以及位址。
設定 Replica Set 服務的 Mongod 設定檔(先不啟用驗證模式)
vi /etc/mongod.co
systemLog:
destination: file
logAppend: true
path: /var/log/mongodb/mongod.log
storage:
dbPath: /home/mongod
journal:
enabled: true
processManagement:
fork: true
pidFilePath: /var/run/mongodb/mongod.pid # location of pidfile
net:
port: 27019
bindIp: 0.0.0.0
這裡我們將 Replica Set 服務設定在 27019 Port,主要是因為之後會繼續建立 Sharding 架構,刻意避開標準的 27017 Port,保留 27017 Port 給之後的 Mongo Router 使用。如果您不打算建構 Sharding,那就直接使用 27017 即可,讓應用程式端不需要修改就可以使用。修改完設定檔後記得重新啟動 mongod 服務:
systemctl start mongod
先連線進到第一台 mongod 設定管理者帳密,上述可先在第一台伺服器設置(primary)
mongo mongsh1:27019
use admin
db.createUser( {
user: "myUserAdmin",
pwd: "",
roles: [ { role: "userAdminAnyDatabase", db: "admin" } ]
});
db.createUser( {
user: "siteRootAdmin",
pwd: "",
roles: [ { role: "root", db: "admin" } ]
});
也可以多新增一個admin帳號
db.createUser( {
user: "admin",
pwd: "",
roles: [ { role: "root", db: "admin" } ]
});
接著,透過以下命令建立一個 Key,並且複製到每一台機器 (mongsh1, mongsh2, mongsh3),之後每個 Mongod 實體會透過這把 Key 進行資料同步,接下來的動作比較複雜,順序不可以搞錯。很多人在這裡搞不定驗證功能,索性關閉驗證服務,這樣其實比較沒有保障,乖乖啟用驗證還是比較好的。
openssl rand -base64 741 > /home/mongod/mongodb-keyfile
chmod 600 /home/mongod/mongodb-keyfile
chown mongodb.mongodb /home/mongod/mongodb-keyfile
記得把這把 Key 放到每一台機器的 /home/mongodb-keyfile 檔案中。接下來我們就要啟用 Replica Set 與認證模式囉。再度編輯 /etc/mongod.conf 設定檔:
vim /etc/mongod.conf
security:
keyFile: /var/lib/mongo/mongodb-keyfile
replication:
replSetName: rs
在另外兩台伺服器可以修改設定檔為下
systemLog:
destination: file
logAppend: true
path: /var/log/mongodb/mongod.log
storage:
dbPath: /home/mongod
journal:
enabled: true
processManagement:
fork: true
pidFilePath: /var/run/mongodb/mongod.pid # location of pidfile
net:
port: 27019
bindIp: 0.0.0.0
security:
keyFile: /home/mongod/mongodb-keyfile
replication:
replSetName: bes
重新啟動 mongod 服務(另外兩台也要喔)
systemctl restart mongod
連線至剛剛的第一台 Mongod 並初始化 Replica Set,如下:
mongo mongsh1:27019
use admin
db.auth("siteRootAdmin", "");
rs.initiate()
rs.conf()
注意:正常完成時會有下面訊息出現:
接著新增另外兩台 Replica Set 節點,輸入以下命令:
rs.add("mongsh2:27019")
rs.add("mongsh3:27019")
rs.status()
注意:正常完成時會有下面訊息出現:
bes:PRIMARY> rs.status()
{
"set" : "bes",
"date" : ISODate("2017-09-09T14:51:02.381Z"),
"myState" : 1,
"term" : NumberLong(3),
"heartbeatIntervalMillis" : NumberLong(2000),
"optimes" : {
"lastCommittedOpTime" : {
"ts" : Timestamp(1504968659, 1),
"t" : NumberLong(3)
},
"appliedOpTime" : {
"ts" : Timestamp(1504968659, 1),
"t" : NumberLong(3)
},
"durableOpTime" : {
"ts" : Timestamp(1504968659, 1),
"t" : NumberLong(3)
}
},
"members" : [
{
"_id" : 0,
"name" : "mongsh1:27019",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 4051,
"optime" : {
"ts" : Timestamp(1504968659, 1),
"t" : NumberLong(3)
},
"optimeDate" : ISODate("2017-09-09T14:50:59Z"),
"electionTime" : Timestamp(1504964638, 1),
"electionDate" : ISODate("2017-09-09T13:43:58Z"),
"configVersion" : 67972,
"self" : true
},
{
"_id" : 1,
"name" : "mongsh2:27019",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 2961,
"optime" : {
"ts" : Timestamp(1504968659, 1),
"t" : NumberLong(3)
},
"optimeDurable" : {
"ts" : Timestamp(1504968659, 1),
"t" : NumberLong(3)
},
"optimeDate" : ISODate("2017-09-09T14:50:59Z"),
"optimeDurableDate" : ISODate("2017-09-09T14:50:59Z"),
"lastHeartbeat" : ISODate("2017-09-09T14:51:00.676Z"),
"lastHeartbeatRecv" : ISODate("2017-09-09T14:51:01.607Z"),
"pingMs" : NumberLong(0),
"syncingTo" : "mongsh1:27019",
"configVersion" : 67972
},
{
"_id" : 2,
"name" : "mongsh3:27019",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 2961,
"optime" : {
"ts" : Timestamp(1504968659, 1),
"t" : NumberLong(3)
},
"optimeDurable" : {
"ts" : Timestamp(1504968659, 1),
"t" : NumberLong(3)
},
"optimeDate" : ISODate("2017-09-09T14:50:59Z"),
"optimeDurableDate" : ISODate("2017-09-09T14:50:59Z"),
"lastHeartbeat" : ISODate("2017-09-09T14:51:00.676Z"),
"lastHeartbeatRecv" : ISODate("2017-09-09T14:51:01.606Z"),
"pingMs" : NumberLong(0),
"syncingTo" : "mongsh1:27019",
"configVersion" : 67972
}
],
"ok" : 1
}
bes:PRIMARY>
這樣就完成了,但如果出現有Statup誒
如果有伺服器出現:
“stateStr” : “STARTUP”,
例如:
bes:PRIMARY> rs.status()
{
"set" : "bes",
"date" : ISODate("2017-09-09T14:51:02.381Z"),
"myState" : 1,
"term" : NumberLong(3),
"heartbeatIntervalMillis" : NumberLong(2000),
"optimes" : {
"lastCommittedOpTime" : {
"ts" : Timestamp(1504968659, 1),
"t" : NumberLong(3)
},
"appliedOpTime" : {
"ts" : Timestamp(1504968659, 1),
"t" : NumberLong(3)
},
"durableOpTime" : {
"ts" : Timestamp(1504968659, 1),
"t" : NumberLong(3)
}
},
"members" : [
{
"_id" : 0,
"name" : "mongsh1:27019",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 4051,
"optime" : {
"ts" : Timestamp(1504968659, 1),
"t" : NumberLong(3)
},
"optimeDate" : ISODate("2017-09-09T14:50:59Z"),
"electionTime" : Timestamp(1504964638, 1),
"electionDate" : ISODate("2017-09-09T13:43:58Z"),
"configVersion" : 67972,
"self" : true
},
{
"_id" : 1,
"name" : "mongsh2:27019",
"health" : 1,
"state" : 0,
"stateStr" : "STARTUP",
"uptime" : 2961,
"optime" : {
"ts" : Timestamp(1504968659, 1),
"t" : NumberLong(3)
},
"optimeDurable" : {
"ts" : Timestamp(1504968659, 1),
"t" : NumberLong(3)
},
"optimeDate" : ISODate("2017-09-09T14:50:59Z"),
"optimeDurableDate" : ISODate("2017-09-09T14:50:59Z"),
"lastHeartbeat" : ISODate("2017-09-09T14:51:00.676Z"),
"lastHeartbeatRecv" : ISODate("2017-09-09T14:51:01.607Z"),
"pingMs" : NumberLong(0),
"syncingTo" : "mongsh1:27019",
"configVersion" : 67972
},
{
"_id" : 2,
"name" : "mongsh3:27019",
"health" : 1,
"state" : 0,
"stateStr" : "STARTUP",
"uptime" : 2961,
"optime" : {
"ts" : Timestamp(1504968659, 1),
"t" : NumberLong(3)
},
"optimeDurable" : {
"ts" : Timestamp(1504968659, 1),
"t" : NumberLong(3)
},
"optimeDate" : ISODate("2017-09-09T14:50:59Z"),
"optimeDurableDate" : ISODate("2017-09-09T14:50:59Z"),
"lastHeartbeat" : ISODate("2017-09-09T14:51:00.676Z"),
"lastHeartbeatRecv" : ISODate("2017-09-09T14:51:01.606Z"),
"pingMs" : NumberLong(0),
"syncingTo" : "mongsh1:27019",
"configVersion" : 67972
}
],
"ok" : 1
}
#mongo localhost:27019
bes:PRIMARY> (有時候出現是bes:SECONDARY>,都可以設置)
bes:PRIMARY>use admin
bes:PRIMARY>db.auth("siteRootAdmin","")
bes:PRIMARY>var cfg={_id:"bes",members:[{_id:0,host:"mongsh1:27019"},{_id:1,host:"mongsh2:27019"},{_id:2,host:"mongsh3:27019"}]}
bes:PRIMARY>rs.reconfig(cfg)
bes:PRIMARY>rs.status()
這樣就大功告成了!!!
Reference:
MongoDB Replica Set 高可用性架構搭建
mongodb 副本集搭建