mongodb副本集介紹
MongoDB副本集早期是沒有這個概念的,早期MongoDB是使用master-slave模式,一主一從和MySQL功能類似,當主庫宕機後,從庫不能自動切換成主
目前版本已經不再使用master-slave模式了,改爲使用副本集,這種模式下有一個主(primary),多個從角色(seconday),從角色是隻讀。可以爲副本集設置權重,當主宕機後,剩下權重最高的機器切換成爲主角色
在此架構中還可以建立一個仲裁角色(arbiter) ,它只負責對主從切換做裁決,不存儲任何數據
在此架構中讀寫數據都是在主上,想要實現負載均衡目的需要手動指定讀庫的目標server。在程序代碼中實現主寫入數據,然後從slave讀取數據
當一個promary宕機後,羣集內的secondary會根據優先級選出新的primary出來,如果故障的primary恢復後則羣集副本中再次根據優先級來裁決新的主角色,這時候就根據設定的優先級來決定誰是主誰是從,根據優先級來選舉不會容易出現"腦裂"的情況發生
mongodb副本集搭建
三臺服務器上都指定yum源配置文件(如果時間太久導致該yum源不可用,請到官網自行尋找最新配置):
[root@nfs1 ~]# cat /etc/yum.repos.d/mongodb.repo
[mongodb-org-4.0]
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/4.0/x86_64/
gpgcheck=1
enabled=1
gpgkey=https://www.mongodb.org/static/pgp/server-4.0.asc
三臺服務器都安裝mongodb服務
192.168.1.234(primary)、192.168.1.115(secondary)、192.168.1.200(secondary)
三臺服務器編輯配置文件,更改或增加:
replication 把此行註釋的#號刪除掉,然後定義oplog大小
##oplog定義大小,在這個配置項前有兩個空格,數值前必須有一個空格符
oplogSizeMB: 20
##複製集名稱,配置項前面需要添加兩個空格符,定義名字前必須有一個空格符
replSetName:linux
修改配置文件內容,配置文件中需要針對bindIp這個有不一樣的配置,是要配置成自己的網卡ip
[root@nfs1 ~]# vim /etc/mongod.conf
net:
port: 27017
bindIp: 127.0.0.1,192.168.1.234 # Enter 0.0.0.0,:: to bind to all IPv4 and IPv6 addresses or, alternatively, use the net.bindIpAll setting.
#security:
#operationProfiling:
replication:
oplogSizeMB: 20
replSetName: linux
#sharding:
重啓mongodb服務,並查看啓動進程和監聽的端口信息
[root@nfs1 ~]# ps -aux |grep mongod
mongod 11794 0.3 8.4 1072464 84140 ? Sl 14:52 0:32 /usr/bin/mongod -f /etc/mongod.conf
root 11919 0.0 0.0 112652 960 pts/1 S+ 17:37 0:00 grep --color=auto mongod
[root@nfs1 ~]# netstat -ntlp |grep mongod
tcp 0 0 192.168.1.115:27017 0.0.0.0:* LISTEN 11794/mongod
tcp 0 0 127.0.0.1:27017 0.0.0.0:* LISTEN 11794/mongod
在配置副本集前先要確認每臺服務器上都沒有iptables規則
然後登入到需要指定主的服務器上,指定副本集的服務器。id:0爲主服務器,id:1、id:2爲從服務器
在執行rs.initiate(config)初始化副本集後可以看到提示有ok:1的信息。表示副本集創建成功
[root@nfs1 ~]# mongo
MongoDB shell version v4.0.4
connecting to: mongodb://127.0.0.1:27017
Implicit session: session { "id" : UUID("a6f3940f-b5e7-4444-8b79-9e12bcdbd21a") }
MongoDB server version: 4.0.4
> config={_id:"linux",members:[{_id:0,host:"192.168.1.234:27017"},{_id:1,host:"192.168.1.115:27017"},{_id:2,host:"192.168.1.200:27017"}]}
{
"_id" : "linux",
"members" : [
{
"_id" : 0,
"host" : "192.168.1.234:27017"
},
{
"_id" : 1,
"host" : "192.168.1.115:27017"
},
{
"_id" : 2,
"host" : "192.168.1.200:27017"
}
]
}
linux:SECONDARY> rs.initiate(config)
> rs.initiate(config)
{
"ok" : 1,
"operationTime" : Timestamp(1542718739, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1542718739, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
這裏我出現一個問題,指定了兩個"SECONDARY"服務器,但是rs.status出來的只有兩臺,歸根原因是網絡問題,原因是因爲115機器上的iptables沒有清除乾淨,導致mongodb間通信出現問題,清空iptables規則就可以了
查看mongodb的副本集狀態
rs.status()
執行狀態查詢後可以看到1.234的狀態是PRIMARY角色,其他機器是SECONDARY角色
linux:SECONDARY> rs.status()
{
"set" : "linux",
"date" : ISODate("2018-11-20T13:00:08.697Z"),
"myState" : 1,
"term" : NumberLong(1),
"syncingTo" : "",
"syncSourceHost" : "",
"syncSourceId" : -1,
"heartbeatIntervalMillis" : NumberLong(2000),
"optimes" : {
"lastCommittedOpTime" : {
"ts" : Timestamp(1542718802, 1),
"t" : NumberLong(1)
},
"readConcernMajorityOpTime" : {
"ts" : Timestamp(1542718802, 1),
"t" : NumberLong(1)
},
"appliedOpTime" : {
"ts" : Timestamp(1542718802, 1),
"t" : NumberLong(1)
},
"durableOpTime" : {
"ts" : Timestamp(1542718802, 1),
"t" : NumberLong(1)
}
},
"lastStableCheckpointTimestamp" : Timestamp(1542718752, 1),
"members" : [
{
"_id" : 0,
"name" : "192.168.1.234:27017",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 1999,
"optime" : {
"ts" : Timestamp(1542718802, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2018-11-20T13:00:02Z"),
"syncingTo" : "",
"syncSourceHost" : "",
"syncSourceId" : -1,
"infoMessage" : "could not find member to sync from",
"electionTime" : Timestamp(1542718751, 1),
"electionDate" : ISODate("2018-11-20T12:59:11Z"),
"configVersion" : 1,
"self" : true,
"lastHeartbeatMessage" : ""
},
{
"_id" : 1,
"name" : "192.168.1.115:27017",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 68,
"optime" : {
"ts" : Timestamp(1542718802, 1),
"t" : NumberLong(1)
},
"optimeDurable" : {
"ts" : Timestamp(1542718802, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2018-11-20T13:00:02Z"),
"optimeDurableDate" : ISODate("2018-11-20T13:00:02Z"),
"lastHeartbeat" : ISODate("2018-11-20T13:00:07.254Z"),
"lastHeartbeatRecv" : ISODate("2018-11-20T13:00:07.078Z"),
"pingMs" : NumberLong(0),
"lastHeartbeatMessage" : "",
"syncingTo" : "192.168.1.234:27017",
"syncSourceHost" : "192.168.1.234:27017",
"syncSourceId" : 0,
"infoMessage" : "",
"configVersion" : 1
},
{
"_id" : 2,
"name" : "192.168.1.200:27017",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 68,
"optime" : {
"ts" : Timestamp(1542718802, 1),
"t" : NumberLong(1)
},
"optimeDurable" : {
"ts" : Timestamp(1542718802, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2018-11-20T13:00:02Z"),
"optimeDurableDate" : ISODate("2018-11-20T13:00:02Z"),
"lastHeartbeat" : ISODate("2018-11-20T13:00:07.268Z"),
"lastHeartbeatRecv" : ISODate("2018-11-20T13:00:07.680Z"),
"pingMs" : NumberLong(1),
"lastHeartbeatMessage" : "",
"syncingTo" : "192.168.1.115:27017",
"syncSourceHost" : "192.168.1.115:27017",
"syncSourceId" : 1,
"infoMessage" : "",
"configVersion" : 1
}
],
"ok" : 1,
"operationTime" : Timestamp(1542718802, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1542718802, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
mongodb刪除副本集
rs.remove("ip:port")
>rs.remove("192.168.1.115:27017")
mongodb副本集測試
在主上創建庫,創建一個測試集合。並查看該集合的狀態
linux:PRIMARY> use mydb
switched to db mydb
linux:PRIMARY> db.acc.insert({AccountID:1,UserName:"linux",password:"pwd@123"})
WriteResult({ "nInserted" : 1 })
linux:PRIMARY> show dbs;
admin 0.000GB
config 0.000GB
local 0.000GB
mydb 0.000GB
linux:PRIMARY> show tables
acc
在啓用副本集後,從上是不能正常查詢集合的。還需要設定從上的副本集的配置,參考如下:
一開始執行show dbs會出現錯誤信息:
linux:SECONDARY> show dbs
2018-11-20T21:37:43.395+0800 E QUERY [js] Error: listDatabases failed:{
"operationTime" : Timestamp(1542721053, 1),
"ok" : 0,
"errmsg" : "not master and slaveOk=false",
解決這個錯誤信息需要執行從上的初始化,然後就可以正常查詢到庫和集合了
linux:SECONDARY> rs.slaveOk()
linux:SECONDARY> show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
mydb 0.000GB
linux:SECONDARY> use mydb
switched to db mydb
linux:SECONDARY> show tables
acc
指定mongodb的主從權重
默認三臺機器權重都爲1,如果任何一個權重設定爲比其他機器高,則該臺機器會馬上切換成primary角色,所以這裏將三臺機器設定爲:
192.168.1.234id爲0,權重爲3
192.168.1.115id爲1,權重爲2
192.168.1.200id爲2,權重爲1
操作只在主上執行,在主機器上執行以下語句:
linux:PRIMARY> cfg = rs.conf()
linux:PRIMARY> cfg.members[0].priority = 3
3
linux:PRIMARY> cfg.members[1].priority = 2
2
linux:PRIMARY> cfg.members[2].priority = 1
1
linux:PRIMARY> rs.reconfig(cfg)
{
"ok" : 1,
"operationTime" : Timestamp(1542722379, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1542722379, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
再次查看權重狀態分配,權重信息再"priority" : 表示權重優先級
linux:PRIMARY> rs.config()
{
"_id" : "linux",
"version" : 6,
"protocolVersion" : NumberLong(1),
"writeConcernMajorityJournalDefault" : true,
"members" : [
{
"_id" : 0,
"host" : "192.168.1.234:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 3,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
},
{
"_id" : 1,
"host" : "192.168.1.115:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 2,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
},
{
"_id" : 2,
"host" : "192.168.1.200:27017",
"arbiterOnly" : false,
"buildIndexes" : true,
"hidden" : false,
"priority" : 1,
"tags" : {
},
"slaveDelay" : NumberLong(0),
"votes" : 1
}
],
"settings" : {
"chainingAllowed" : true,
"heartbeatIntervalMillis" : 2000,
"heartbeatTimeoutSecs" : 10,
"electionTimeoutMillis" : 10000,
"catchUpTimeoutMillis" : -1,
"catchUpTakeoverDelayMillis" : 30000,
"getLastErrorModes" : {
},
"getLastErrorDefaults" : {
"w" : 1,
"wtimeout" : 0
},
"replicaSetId" : ObjectId("5bf4051352f0b9218cdf373c")
}
}
這樣配置完成後,主宕機後,第二個節點會成爲候選的主節點
測試:
在主上開啓iptables,禁止掉mongod的數據流量,查看副本集會如何切換,是否切換到了第二節點
[root@nfs1 /]# iptables -I INPUT -p tcp --dport 27017 -j DROP