參考:
https://www.cnblogs.com/kevingrace/p/7881496.html
http://www.lxweimin.com/p/f9f1454f251f
一、介紹
MongoDB復(fù)制集是一個帶有故障轉(zhuǎn)移的主從集群。是從現(xiàn)有的主從模式演變而來,增加了自動故障轉(zhuǎn)移和節(jié)點(diǎn)成員自動恢復(fù)。MongoDB復(fù)制集模式中沒有固定的主節(jié)點(diǎn),在啟動后,多個服務(wù)節(jié)點(diǎn)間將自動選舉產(chǎn)生一個主節(jié)點(diǎn)。該主節(jié)點(diǎn)被稱為primary,一個或多個從節(jié)點(diǎn)被稱為secondaries。primary節(jié)點(diǎn)基本上就是master結(jié)點(diǎn),不同之處在于primary結(jié)點(diǎn)在不同時間可能是不同的服務(wù)器。如果當(dāng)前的主結(jié)點(diǎn)失效了,復(fù)制集中的其余結(jié)點(diǎn)將會試圖選出一個新的主結(jié)點(diǎn)。
MongoDB復(fù)制集模式的好處:
- 一切自動化。首先,復(fù)制集模式本身做了大量的管理工作,自動管理從節(jié)點(diǎn),確保數(shù)據(jù)不會不一致。
- 主節(jié)點(diǎn)掛掉后,會自動判斷集群中的服務(wù)器并進(jìn)行故障轉(zhuǎn)移,推舉新的主節(jié)點(diǎn)。
- 一個復(fù)制集集群支持1-7臺服務(wù)器,在一個復(fù)制集中各個服務(wù)器數(shù)據(jù)保持完全一致。
在一個MongoDB復(fù)制集集群中,各個服務(wù)器有以下幾種狀態(tài):
- Primary 主節(jié)點(diǎn),一個復(fù)制集有且僅有一臺服務(wù)器處于Primary狀態(tài),只有主節(jié)點(diǎn)才對外提供讀寫服務(wù)。如果主節(jié)點(diǎn)掛掉,復(fù)制集將投票選出一個備節(jié)點(diǎn)成為新的主節(jié)點(diǎn)。
- Secondary 備用節(jié)點(diǎn),復(fù)制集允許有多臺Secondary,每個備用節(jié)點(diǎn)的數(shù)據(jù)與主節(jié)點(diǎn)的數(shù)據(jù)是完全同步的。Recovering 恢復(fù)中,當(dāng)復(fù)制集中某臺服務(wù)器掛掉或者掉線后數(shù)據(jù)無法同步,重新恢復(fù)服務(wù)后從其他成員復(fù)制數(shù)據(jù),這時就處于恢復(fù)過程,數(shù)據(jù)同步后,該節(jié)點(diǎn)又回到備用狀態(tài)。
- Arbiter 仲裁節(jié)點(diǎn),該類節(jié)點(diǎn)可以不用單獨(dú)存在,如果配置為仲裁節(jié)點(diǎn),就主要負(fù)責(zé)在復(fù)本集中監(jiān)控其他節(jié)點(diǎn)狀態(tài),投票選出主節(jié)點(diǎn)。該節(jié)點(diǎn)將不會用于存放數(shù)據(jù)。如果沒有仲裁節(jié)點(diǎn),那么投票工作將由所有節(jié)點(diǎn)共同進(jìn)行。
- Down 無效節(jié)點(diǎn),當(dāng)服務(wù)器掛掉或掉線時就會處于該狀態(tài)。復(fù)制集的從節(jié)點(diǎn)讀請求,也是在各個Driver層設(shè)置slaveOk的值來實(shí)現(xiàn)的。
如上介紹所知,mongodb中的復(fù)制可以在多臺服務(wù)器中同步數(shù)據(jù)。復(fù)制提供了冗余和增加了數(shù)據(jù)的高可用性,防止單個節(jié)點(diǎn)易丟失數(shù)據(jù)的可能性,也可以用來進(jìn)行讀寫分離提高客戶端操作性能。復(fù)制集中各節(jié)點(diǎn)的mongodb實(shí)例有相同的數(shù)據(jù)集副本。主節(jié)點(diǎn)可以接收客戶端所有寫操作記錄到日志中,從庫復(fù)制主庫的操作日志記錄應(yīng)用到其數(shù)據(jù)庫中。一個客戶端只能有一個主節(jié)點(diǎn),如果主節(jié)點(diǎn)不可用(10秒內(nèi)無法連接),復(fù)制集中將選一個成員節(jié)點(diǎn)作為主節(jié)點(diǎn)。MongoDB主備+仲裁的基本結(jié)構(gòu)如下:
-
主節(jié)點(diǎn)(Primary)
在復(fù)制集中,主節(jié)點(diǎn)是唯一能夠接收寫請求的節(jié)點(diǎn)。MongoDB在主節(jié)點(diǎn)進(jìn)行寫操作,并將這些操作記錄到主節(jié)點(diǎn)的oplog中。而從節(jié)點(diǎn)將會從oplog復(fù)制到其本機(jī),并將這些操作應(yīng)用到自己的數(shù)據(jù)集上。(復(fù)制集最多只能擁有一個主節(jié)點(diǎn)) -
從節(jié)點(diǎn)(Secondaries)
從節(jié)點(diǎn)通過應(yīng)用主節(jié)點(diǎn)傳來的數(shù)據(jù)變動操作來保持其數(shù)據(jù)集與主節(jié)點(diǎn)一致。從節(jié)點(diǎn)也可以通過增加額外參數(shù)配置來對應(yīng)特殊需求。例如,從節(jié)點(diǎn)可以是non-voting或是priority 0. -
仲裁節(jié)點(diǎn)(ARBITER)
仲裁節(jié)點(diǎn)即投票節(jié)點(diǎn),其本身并不包含數(shù)據(jù)集,且也無法晉升為主節(jié)點(diǎn)。但是,旦當(dāng)前的主節(jié)點(diǎn)不可用時,投票節(jié)點(diǎn)就會參與到新的主節(jié)點(diǎn)選舉的投票中。仲裁節(jié)點(diǎn)使用最小的資源并且不要求硬件設(shè)備。投票節(jié)點(diǎn)的存在使得復(fù)制集可以以偶數(shù)個節(jié)點(diǎn)存在,而無需為復(fù)制集再新增節(jié)點(diǎn) 不要將投票節(jié)點(diǎn)運(yùn)行在復(fù)制集的主節(jié)點(diǎn)或從節(jié)點(diǎn)機(jī)器上。 投票節(jié)點(diǎn)與其他 復(fù)制集節(jié)點(diǎn)的交流僅有:選舉過程中的投票,心跳檢測和配置數(shù)據(jù)。這些交互都是不加密的。
心跳檢測
復(fù)制集成員每兩秒向復(fù)制集中其他成員進(jìn)行心跳檢測。如果某個節(jié)點(diǎn)在10秒內(nèi)沒有返回,那么它將被標(biāo)記為不可用。
二、安裝
1.下載mongodb
https://www.mongodb.com/download-center/community
選擇版本,本例選擇最新4.2.3,服務(wù)器上用wget下載
wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-4.2.3.tgz
2.配置
- 解壓
tar -xzvf mongodb-linux-x86_64-rhel70-4.2.3.tgz
- 重命名為
mv mongodb-linux-x86_64-rhel70-4.2.3/ mongodb
- 在mongodb目錄新建data logs conf文件夾
cd mongodb
mkdir data logs conf
- conf中新建配置文件
vi conf/mongodb.conf
#內(nèi)容如下:
systemLog:
destination: file
path: "/home/cluster/mongodb/logs/mongod.log"
logAppend: true
storage:
dbPath: "/home/cluster/mongodb/data"
journal:
enabled: true
processManagement:
fork: true # fork and run in background
timeZoneInfo: /usr/share/zoneinfo
net:
bindIp: 192.168.62.15
port: 28017
replication:
oplogSizeMB: 1024
replSetName: rs0
3.添加用戶環(huán)境變量
vi .bash_profile
#文件末尾加上
export PATH=$PATH:/home/cluster/mongodb/bin
4.注冊為系統(tǒng)服務(wù)
vi /lib/systemd/system/mongodb.service
#內(nèi)容如下:
[Unit]
Description=MongoDB Database Server
Documentation=https://docs.mongodb.org/manual
After=network.target remote-fs.target nss-lookup.target
[Service]
Type=forking
User=cluster
Group=cluster
ExecStart=/home/cluster/mongodb/bin/mongod --config /home/cluster/mongodb/conf/mongodb.conf
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/home/cluster/mongodb/bin/mongod --config /home/cluster/mongodb/conf/mongodb.conf --shutdown
PrivateTmp=true
[Install]
WantedBy=multi-user.target
三、啟動
#關(guān)閉mongodb
mongod -f /home/cluster/mongodb/conf/mongodb.conf --shutdown
#使用配置文件啟動mongodb
mongod -f /home/cluster/mongodb/conf/mongodb.conf
systemctl start mongodb.service
systemctl stop mongodb.service
四、配置集群
192.168.62.37 Primary
192.168.62.15 Secondary
192.168.62.95 Arbiter
#連接主節(jié)點(diǎn)
mongo 192.168.62.15:28037
#初始化集群
rs.initiate({_id: "rs0",members: [{ _id: 0 , host: "192.168.62.37:28017" }]})
#添加副節(jié)點(diǎn)
rs.add("192.168.62.15:28017")
#添加仲裁節(jié)點(diǎn)
rs.addArb("192.168.62.95:28017")
#查看狀態(tài)
rs0:PRIMARY> rs.status();
{
"set" : "rs0",
"date" : ISODate("2020-03-23T09:22:37.763Z"),
"myState" : 1,
"term" : NumberLong(5),
"syncingTo" : "",
"syncSourceHost" : "",
"syncSourceId" : -1,
"heartbeatIntervalMillis" : NumberLong(2000),
"majorityVoteCount" : 2,
"writeMajorityCount" : 2,
"optimes" : {
"lastCommittedOpTime" : {
"ts" : Timestamp(1584955352, 1),
"t" : NumberLong(5)
},
"lastCommittedWallTime" : ISODate("2020-03-23T09:22:32.126Z"),
"readConcernMajorityOpTime" : {
"ts" : Timestamp(1584955352, 1),
"t" : NumberLong(5)
},
"readConcernMajorityWallTime" : ISODate("2020-03-23T09:22:32.126Z"),
"appliedOpTime" : {
"ts" : Timestamp(1584955352, 1),
"t" : NumberLong(5)
},
"durableOpTime" : {
"ts" : Timestamp(1584955352, 1),
"t" : NumberLong(5)
},
"lastAppliedWallTime" : ISODate("2020-03-23T09:22:32.126Z"),
"lastDurableWallTime" : ISODate("2020-03-23T09:22:32.126Z")
},
"lastStableRecoveryTimestamp" : Timestamp(1584955322, 1),
"lastStableCheckpointTimestamp" : Timestamp(1584955322, 1),
"electionCandidateMetrics" : {
"lastElectionReason" : "electionTimeout",
"lastElectionDate" : ISODate("2020-03-23T09:11:51.967Z"),
"electionTerm" : NumberLong(5),
"lastCommittedOpTimeAtElection" : {
"ts" : Timestamp(1584954671, 1),
"t" : NumberLong(3)
},
"lastSeenOpTimeAtElection" : {
"ts" : Timestamp(1584954671, 1),
"t" : NumberLong(3)
},
"numVotesNeeded" : 2,
"priorityAtElection" : 1,
"electionTimeoutMillis" : NumberLong(10000),
"numCatchUpOps" : NumberLong(0),
"newTermStartDate" : ISODate("2020-03-23T09:11:52.111Z"),
"wMajorityWriteAvailabilityDate" : ISODate("2020-03-23T09:14:02.372Z")
},
"members" : [
{
"_id" : 0,
"name" : "192.168.62.37:28017",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 755,
"optime" : {
"ts" : Timestamp(1584955352, 1),
"t" : NumberLong(5)
},
"optimeDate" : ISODate("2020-03-23T09:22:32Z"),
"syncingTo" : "",
"syncSourceHost" : "",
"syncSourceId" : -1,
"infoMessage" : "",
"electionTime" : Timestamp(1584954711, 1),
"electionDate" : ISODate("2020-03-23T09:11:51Z"),
"configVersion" : 3,
"self" : true,
"lastHeartbeatMessage" : ""
},
{
"_id" : 1,
"name" : "192.168.62.15:28017",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 515,
"optime" : {
"ts" : Timestamp(1584955352, 1),
"t" : NumberLong(5)
},
"optimeDurable" : {
"ts" : Timestamp(1584955352, 1),
"t" : NumberLong(5)
},
"optimeDate" : ISODate("2020-03-23T09:22:32Z"),
"optimeDurableDate" : ISODate("2020-03-23T09:22:32Z"),
"lastHeartbeat" : ISODate("2020-03-23T09:22:36.033Z"),
"lastHeartbeatRecv" : ISODate("2020-03-23T09:22:36.372Z"),
"pingMs" : NumberLong(0),
"lastHeartbeatMessage" : "",
"syncingTo" : "192.168.62.37:28017",
"syncSourceHost" : "192.168.62.37:28017",
"syncSourceId" : 0,
"infoMessage" : "",
"configVersion" : 3
},
{
"_id" : 2,
"name" : "192.168.62.95:28017",
"health" : 1,
"state" : 7,
"stateStr" : "ARBITER",
"uptime" : 753,
"lastHeartbeat" : ISODate("2020-03-23T09:22:35.972Z"),
"lastHeartbeatRecv" : ISODate("2020-03-23T09:22:36.371Z"),
"pingMs" : NumberLong(0),
"lastHeartbeatMessage" : "",
"syncingTo" : "",
"syncSourceHost" : "",
"syncSourceId" : -1,
"infoMessage" : "",
"configVersion" : 3
}
],
"ok" : 1,
"$clusterTime" : {
"clusterTime" : Timestamp(1584955352, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
},
"operationTime" : Timestamp(1584955352, 1)
}
五、開啟驗證
在副本集內(nèi)成員之間需要用keyFile認(rèn)證,集群所有mongod和mongos實(shí)例使用內(nèi)容相同的keyFile文件;由于啟用了認(rèn)證,需要建立一個管理員帳號,才能從遠(yuǎn)程登錄。建立管理員帳戶,利用管理員賬戶從遠(yuǎn)程登錄后,需要建立一個可以操作某個數(shù)據(jù)庫的用戶,客戶端就用這個用戶訪問數(shù)據(jù)庫。
- 1.建立管理員賬戶
use admin
db.createUser({
user:"root",
pwd:"123456",
roles: [ { role: "root",db:"admin"}]
})
db.auth("root","123456")//認(rèn)證該用戶
- 2.用openssl生成keyFile認(rèn)證文件
openssl rand -base64 700 > mdb-keyfile.jks
#長度不能太長,否則會報如下錯誤,此處定義700長度:
#security key in /home/cluster/mongodb/conf/mdb-keyfile.jks has length 1368, must be between 6 and 1024 chars
- 3.更改keyfile權(quán)限
chmod 600 mdb-keyfile.jks
- 4.拷貝到其他主機(jī)
scp -P 22 mdb-keyfile.jks cluster@192.168.62.95:/home/cluster/mongodb/conf
scp -P 22 mdb-keyfile.jks cluster@192.168.62.37:/home/cluster/mongodb/conf
- 5.配置mongodb.conf文件開啟auth認(rèn)證
#配置文件增加:
security:
authorization: enabled
keyFile: /home/cluster/mongodb/conf/mdb-keyfile.jks
- 6.登陸
mongo 192.168.62.37:28017/admin -u root -p 123456
mongo 192.168.62.15:28017/admin -u root -p 123456
- 7.連接字符串
mongodb://192.168.62.37:28017,192.168.62.15:28017/?replicaSet=rs0
六、常用操作語句
show dbs;顯示所有存在的數(shù)據(jù)庫
use test;進(jìn)入數(shù)據(jù)庫
db;顯示當(dāng)前所在數(shù)據(jù)庫
show collections;顯示當(dāng)前數(shù)據(jù)庫所有集合
//向當(dāng)前數(shù)據(jù)庫,students集合中插入一個學(xué)生文檔
db.students.insert({"name":"孫悟空","age":18,"sex":"男"});
//向當(dāng)前數(shù)據(jù)庫,students集合中插入多個學(xué)生文檔
db.students.insert([{"name":"紫霞","age":16,"sex":"女"},{"name":"牛魔","age":23,"sex":"男"}]);
db.students.find();查詢當(dāng)前數(shù)據(jù)庫,students集合中所有的文檔
db.students.find({"sex":"男"});查詢當(dāng)前數(shù)據(jù)庫,students集合中符合條件的文檔
db.students.find({"name":/牛/});模糊查詢
db.students.find().count();查詢當(dāng)前數(shù)據(jù)庫,students集合中所有的文檔的總數(shù)
db.students.find().sort({"age":1});根據(jù)字段排序,1正序 -1倒序
db.students.update({"name":"牛魔"}, {$set:{"name":"牛魔魔"}});部分字段更新,默認(rèn)只修改一條記錄
db.students.updateMany({"sex":"男"}, {$set:{"sex":"男生"}});部分字段更新,修改多條記錄
db.students.remove({"name":"牛魔魔"});刪除符合條件的文檔
db.students.drop();刪除當(dāng)前集合
db.dropDatabase();刪除當(dāng)前數(shù)據(jù)庫