1. 程式人生 > >mongodb副本集簡單介紹和建立

mongodb副本集簡單介紹和建立

mongodb副本集介紹

MongoDB副本集早期是沒有這個概念的,早期MongoDB是使用master-slave模式,一主一從和MySQL功能類似,當主庫宕機後,從庫不能自動切換成主

目前版本已經不再使用master-slave模式了,改為使用副本集,這種模式下有一個主(primary),多個從角色(seconday),從角色是隻讀。可以為副本集設定權重,當主宕機後,剩下權重最高的機器切換成為主角色

在此架構中還可以建立一個仲裁角色(arbiter) ,它只負責對主從切換做裁決,不儲存任何資料

在此架構中讀寫資料都是在主上,想要實現負載均衡目的需要手動指定讀庫的目標server。在程式程式碼中實現主寫入資料,然後從slave讀取資料

圖片.png

當一個promary宕機後,群集內的secondary會根據優先順序選出新的primary出來,如果故障的primary恢復後則群集副本中再次根據優先順序來裁決新的主角色,這時候就根據設定的優先順序來決定誰是主誰是從,根據優先順序來選舉不會容易出現"腦裂"的情況發生


圖片.png



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