mongodb副本集簡單介紹和建立
mongodb副本集介紹
MongoDB副本集早期是沒有這個概念的,早期MongoDB是使用master-slave模式,一主一從和MySQL功能類似,當主庫宕機後,從庫不能自動切換成主
目前版本已經不再使用master-slave模式了,改為使用副本集,這種模式下有一個主(primary),多個從角色(seconday),從角色是隻讀。可以為副本集設定權重,當主宕機後,剩下權重最高的機器切換成為主角色
在此架構中還可以建立一個仲裁角色(arbiter) ,它只負責對主從切換做裁決,不儲存任何資料
在此架構中讀寫資料都是在主上,想要實現負載均衡目的需要手動指定讀庫的目標server。在程式程式碼中實現主寫入資料,然後從slave讀取資料
當一個promary宕機後,群集內的secondary會根據優先順序選出新的primary出來,如果故障的primary恢復後則群集副本中再次根據優先順序來裁決新的主角色,這時候就根據設定的優先順序來決定誰是主誰是從,根據優先順序來選舉不會容易出現"腦裂"的情況發生
mongodb副本集搭建
三臺伺服器上都指定yum源配置檔案(如果時間太久導致該yum源不可用,請到官網自行尋找最新配置):
[[email protected] ~]# 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
[[email protected] ~]# 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服務,並檢視啟動程序和監聽的埠資訊
[[email protected] ~]# 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
[[email protected] ~]# 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的資訊。表示副本集建立成功
[[email protected] ~]# 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:"[email protected]"})
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的資料流量,檢視副本集會如何切換,是否切換到了第二節點
[[email protected] /]# iptables -I INPUT -p tcp --dport 27017 -j DROP