安裝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: