1. 程式人生 > >MongoDB 復制(副本集)

MongoDB 復制(副本集)

shadow star states screens ... 導致 6.5 status ffffff

一、復制集相關概念
復制集
    復制是在多臺服務器之間同步數據的過程,由一組Mongod實例(進程)組成,包含一個Primary節點和多個Secondary節點
    Mongodb Driver(客戶端)的所有數據都寫入Primary,Secondary從Primary同步寫入的數據
    通過上述方式來保持復制集內所有成員存儲相同的數據集,提供數據的高可用

復制的目的
        Failover (故障轉移,故障切換,故障恢復)
        Redundancy(數據冗余)
        避免單點,用於災難時恢復,報表處理,提升數據可用性
        讀寫分離,分擔讀壓力
        對用戶透明的系統維護升級

復制集的原理
        主節點記錄所有的變更到oplog日誌
        輔助節點(Secondary)復制主節點的oplog日誌並且將這些日誌在輔助節點進行重放(做)
        各個節點之間會定期發送心跳信息,一旦主節點宕機,則觸發選舉一個新的主節點,剩余的輔助節點指向新的主
        10s內各輔助節點無法感知主節點的存在,則開始觸發選舉
        通常1分鐘內完成主輔助節點切換,10-30s內感知主節點故障,10-30s內完成選舉及切換       

復制≠備份
        用戶恢復數據,防止數據丟失,實現災難恢復
        人為誤操作導致數據刪除,程序Bug導致數據損壞等

Primary
        首要復制節點,由選舉產生,提供讀寫服務的節點,產生oplog日誌

Secondary       
        備用(輔助)復制節點,Secondary可以提供讀服務,增加Secondary節點可以提供復制集的讀服務能力
        在故障時,備用節點可以根據設定的優先級別提升為首要節點。提升了復制集的可用性

Arbiter
        Arbiter節點只參與投票,不能被選為Primary,並且不從Primary同步數據     
        Arbiter本身不存儲數據,是非常輕量級的服務。
        當復制集成員為偶數時,最好加入一個Arbiter節點,以提升復制集可用性

技術分享圖片

二、創建復制集

設置環境變量:

[root@server1 ~]# vim ~/.bashrc
技術分享圖片

[root@server1 ~]# source ~/.bashrc

簡述環境變量的區別:

修改方法一

export PATH=/usr/local/mongodb/bin:$PATH
//配置完後可以通過echo $PATH查看配置結果。
生效方法:立即生效
有效期限:臨時改變,只能在當前的終端窗口中有效,當前窗口關閉後就會恢復原有的path配置
用戶局限:僅對當前用戶

修改方法二

通過修改.bashrc文件:
vim ~/.bashrc
//在最後一行添上:
export PATH=/usr/local/mongodb/bin:$PATH

生效方法:(有以下兩種)
1、關閉當前終端窗口,重新打開一個新終端窗口就能生效
2、輸入“source ~/.bashrc”命令,立即生效
有效期限:永久有效
用戶局限:僅對當前用戶

修改方法三

通過修改profile文件:
vim /etc/profile
/export PATH //找到設置PATH的行,添加
export PATH=/usr/local/mongodb/bin:$PATH
生效方法:系統重啟
有效期限:永久有效
用戶局限:對所有用戶


創建實例對應的數據目錄

[root@server1 ~]# mkdir /home/data/{n1,n2,n3}


技術分享圖片


[root@server1 ~]# mongod --replSet repSetTest --dbpath /home/data/n1 --logpath /home/data/n1/n1.log --port 27000 --smallfiles --oplogSize 128 --fork

[root@server1 ~]# mongod --replSet repSetTest --dbpath /home/data/n2 --logpath /home/data/n2/n2.log --port 27001 --smallfiles --oplogSize 128 --fork

[root@server1 ~]# mongod --replSet repSetTest --dbpath /home/data/n3 --logpath /home/data/n3/n3.log --port 27002 --smallfiles --oplogSize 128 --fork

查看相應的端口

技術分享圖片


連接到第一個實例

[root@server1 ~]# mongo localhost:27000


> db.person.insert({name:'cara',age:22})      //提示當前節點非master節點

WriteCommandError({
"operationTime" : Timestamp(0, 0),
"ok" : 0,
"errmsg" : "not master",
"code" : 10107,
"codeName" : "NotMaster",
"$clusterTime" : {
"clusterTime" : Timestamp(0, 0),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
})


//下面我們添加復制集的配置文件

> cfg = {
... '_id':'repSetTest',
... 'members':[
... {'_id':0, 'host': 'localhost:27000'},
... {'_id':1, 'host': 'localhost:27001'},
... {'_id':2, 'host': 'localhost:27002'}
... ]
... }
{
"_id" : "repSetTest",
"members" : [
{
"_id" : 0,
"host" : "localhost:27000"
},
{
"_id" : 1,
"host" : "localhost:27001"
},
{
"_id" : 2,
"host" : "localhost:27002"
}
]
}
>

//復制集通過replSetInitiate命令(或mongo shell的rs.initiate())進行初始化
//初始化後各個成員間開始發送心跳消息,並發起Priamry選舉操作
//獲得『大多數』成員投票支持的節點,會成為Primary,其余節點成為Secondary。
//通常建議將復制集成員數量設置為奇數,以確保在復制集故障的時候能夠正確選舉出Primary。
//對於復制集故障導致無法正確選舉得到Primary的情形下,復制集將無法提供寫服務,處於只讀狀態
> rs.initiate(cfg)          //初始化配置文件

{
"ok" : 1,
"operationTime" : Timestamp(1532397006, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1532397006, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
repSetTest:SECONDARY>


//查看狀態,以下提示27000為主節點,其余2個端口為輔助節點

repSetTest:SECONDARY> rs.status()

{
"set" : "repSetTest",
"date" : ISODate("2018-07-24T01:51:46.017Z"),
"myState" : 1,
"term" : NumberLong(1),
"syncingTo" : "",
"syncSourceHost" : "",
"syncSourceId" : -1,
"heartbeatIntervalMillis" : NumberLong(2000),
"optimes" : {
"lastCommittedOpTime" : {
"ts" : Timestamp(1532397099, 1),
"t" : NumberLong(1)
},
"readConcernMajorityOpTime" : {
"ts" : Timestamp(1532397099, 1),
"t" : NumberLong(1)
},
"appliedOpTime" : {
"ts" : Timestamp(1532397099, 1),
"t" : NumberLong(1)
},
"durableOpTime" : {
"ts" : Timestamp(1532397099, 1),
"t" : NumberLong(1)
}
},
"lastStableCheckpointTimestamp" : Timestamp(1532397079, 1),
"members" : [
{
"_id" : 0,
"name" : "localhost:27000",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY", // 主節點
"uptime" : 873,
"optime" : {
"ts" : Timestamp(1532397099, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2018-07-24T01:51:39Z"),
"syncingTo" : "",
"syncSourceHost" : "",
"syncSourceId" : -1,
"infoMessage" : "could not find member to sync from",
"electionTime" : Timestamp(1532397017, 1),
"electionDate" : ISODate("2018-07-24T01:50:17Z"),
"configVersion" : 1,
"self" : true,
"lastHeartbeatMessage" : ""
},
{
"_id" : 1,
"name" : "localhost:27001",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 99,
"optime" : {
"ts" : Timestamp(1532397099, 1),
"t" : NumberLong(1)
},
"optimeDurable" : {
"ts" : Timestamp(1532397099, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2018-07-24T01:51:39Z"),
"optimeDurableDate" : ISODate("2018-07-24T01:51:39Z"),
"lastHeartbeat" : ISODate("2018-07-24T01:51:45.928Z"),
"lastHeartbeatRecv" : ISODate("2018-07-24T01:51:44.242Z"),
"pingMs" : NumberLong(0),
"lastHeartbeatMessage" : "",
"syncingTo" : "localhost:27000",
"syncSourceHost" : "localhost:27000",
"syncSourceId" : 0,
"infoMessage" : "",
"configVersion" : 1
},
{
"_id" : 2,
"name" : "localhost:27002",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 99,
"optime" : {
"ts" : Timestamp(1532397099, 1),
"t" : NumberLong(1)
},
"optimeDurable" : {
"ts" : Timestamp(1532397099, 1),
"t" : NumberLong(1)
},
"optimeDate" : ISODate("2018-07-24T01:51:39Z"),
"optimeDurableDate" : ISODate("2018-07-24T01:51:39Z"),
"lastHeartbeat" : ISODate("2018-07-24T01:51:45.928Z"),
"lastHeartbeatRecv" : ISODate("2018-07-24T01:51:44.208Z"),
"pingMs" : NumberLong(0),
"lastHeartbeatMessage" : "",
"syncingTo" : "localhost:27000",
"syncSourceHost" : "localhost:27000",
"syncSourceId" : 0,
"infoMessage" : "",
"configVersion" : 1
}
],
"ok" : 1,
"operationTime" : Timestamp(1532397099, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1532397099, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}


//使用isMaster()函數尋找誰是Master

repSetTest:PRIMARY> db.isMaster()
{
"hosts" : [
"localhost:27000",
"localhost:27001",
"localhost:27002"
],
"setName" : "repSetTest",
"setVersion" : 1,
"ismaster" : true,
"secondary" : false,
"primary" : "localhost:27000",
"me" : "localhost:27000",
"electionId" : ObjectId("7fffffff0000000000000001"),
"lastWrite" : {
"opTime" : {
"ts" : Timestamp(1532397409, 1),
"t" : NumberLong(1)
},
"lastWriteDate" : ISODate("2018-07-24T01:56:49Z"),
"majorityOpTime" : {
"ts" : Timestamp(1532397409, 1),
"t" : NumberLong(1)
},
"majorityWriteDate" : ISODate("2018-07-24T01:56:49Z")
},
"maxBsonObjectSize" : 16777216,
"maxMessageSizeBytes" : 48000000,
"maxWriteBatchSize" : 100000,
"localTime" : ISODate("2018-07-24T01:56:59.218Z"),
"logicalSessionTimeoutMinutes" : 30,
"minWireVersion" : 0,
"maxWireVersion" : 7,
"readOnly" : false,
"ok" : 1,
"operationTime" : Timestamp(1532397409, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1532397409, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}

//在主復制集上插入文檔

repSetTest:PRIMARY> db.replTest.insert({_id:1,value:'abc'})
WriteResult({ "nInserted" : 1 })

查看:

repSetTest:PRIMARY> db.replTest.findOne()
{ "_id" : 1, "value" : "abc" }

//連接到從庫查詢,提示not master

[root@server1 ~]# mongo localhost:27001

//開啟slave查詢

repSetTest:SECONDARY> rs.slaveOk(true)
repSetTest:SECONDARY> db.replTest.find()
{ "_id" : 1, "value" : "abc" }

三、復制集自動故障轉移

此時,kill掉27000的進程


技術分享圖片


[root@server1 ~]# kill -9 2098

再次連接會被拒絕

[root@server1 ~]# mongo localhost:27000
MongoDB shell version v4.0.0
connecting to: mongodb://localhost:27000/test
2018-07-24T10:44:22.435+0800 E QUERY [js] Error: couldn't connect to server localhost:27000, connection attempt failed: SocketException: Error connecting to localhost:27000 (127.0.0.1:27000) :: caused by :: Connection refused :
connect@src/mongo/shell/mongo.js:251:13
@(connect):1:6
exception: connect failed

//連接到27001端口,如下面的查詢,27000連接失敗,27002已經提升為PRIMARY

[root@server1 ~]# mongo localhost:27001

repSetTest:SECONDARY> rs.status()
{
"set" : "repSetTest",
"date" : ISODate("2018-07-24T02:46:40.162Z"),
"myState" : 2,
"term" : NumberLong(2),
"syncingTo" : "localhost:27002",
"syncSourceHost" : "localhost:27002",
"syncSourceId" : 2,
"heartbeatIntervalMillis" : NumberLong(2000),
"optimes" : {
"lastCommittedOpTime" : {
"ts" : Timestamp(1532400396, 1),
"t" : NumberLong(2)
},
"readConcernMajorityOpTime" : {
"ts" : Timestamp(1532400396, 1),
"t" : NumberLong(2)
},
"appliedOpTime" : {
"ts" : Timestamp(1532400396, 1),
"t" : NumberLong(2)
},
"durableOpTime" : {
"ts" : Timestamp(1532400396, 1),
"t" : NumberLong(2)
}
},
"lastStableCheckpointTimestamp" : Timestamp(1532400376, 1),
"members" : [
{
"_id" : 0,
"name" : "localhost:27000",
"health" : 0,
"state" : 8,
"stateStr" : "(not reachable/healthy)", // 提示27001不可到達
"uptime" : 0,
"optime" : {
"ts" : Timestamp(0, 0),
"t" : NumberLong(-1)
},
"optimeDurable" : {
"ts" : Timestamp(0, 0),
"t" : NumberLong(-1)
},
"optimeDate" : ISODate("1970-01-01T00:00:00Z"),
"optimeDurableDate" : ISODate("1970-01-01T00:00:00Z"),
"lastHeartbeat" : ISODate("2018-07-24T02:46:40.048Z"),
"lastHeartbeatRecv" : ISODate("2018-07-24T02:43:56.679Z"),
"pingMs" : NumberLong(0),
"lastHeartbeatMessage" : "Error connecting to localhost:27000 (127.0.0.1:27000) :: caused by :: Connection refused",
"syncingTo" : "",
"syncSourceHost" : "",
"syncSourceId" : -1,
"infoMessage" : "",
"configVersion" : -1
},
{
"_id" : 1,
"name" : "localhost:27001",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 4137,
"optime" : {
"ts" : Timestamp(1532400396, 1),
"t" : NumberLong(2)
},
"optimeDate" : ISODate("2018-07-24T02:46:36Z"),
"syncingTo" : "localhost:27002",
"syncSourceHost" : "localhost:27002",
"syncSourceId" : 2,
"infoMessage" : "",
"configVersion" : 1,
"self" : true,
"lastHeartbeatMessage" : ""
},
{
"_id" : 2,
"name" : "localhost:27002",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY", //27002成為PRIMARY

"uptime" : 3391,
"optime" : {
"ts" : Timestamp(1532400396, 1),
"t" : NumberLong(2)
},
"optimeDurable" : {
"ts" : Timestamp(1532400396, 1),
"t" : NumberLong(2)
},
"optimeDate" : ISODate("2018-07-24T02:46:36Z"),
"optimeDurableDate" : ISODate("2018-07-24T02:46:36Z"),
"lastHeartbeat" : ISODate("2018-07-24T02:46:39.798Z"),
"lastHeartbeatRecv" : ISODate("2018-07-24T02:46:38.901Z"),
"pingMs" : NumberLong(0),
"lastHeartbeatMessage" : "",
"syncingTo" : "",
"syncSourceHost" : "",
"syncSourceId" : -1,
"infoMessage" : "",
"electionTime" : Timestamp(1532400244, 1),
"electionDate" : ISODate("2018-07-24T02:44:04Z"),
"configVersion" : 1
}
],
"ok" : 1,
"operationTime" : Timestamp(1532400396, 1),
"$clusterTime" : {
"clusterTime" : Timestamp(1532400396, 1),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}

//重新啟動27000實例

[root@server1 ~]# mongod --replSet repSetTest --dbpath /home/data/n1 --logpath /home/data/n1/n1.log --port 27000 --smallfiles --oplogSize 128 --fork
2018-07-24T10:51:56.523+0800 I CONTROL [main] Automatically disabling TLS 1.0, to force-enable TLS 1.0 specify --sslDisabledProtocols 'none'
about to fork child process, waiting until server is ready for connections.
forked process: 2598
child process started successfully, parent exiting

//再次查看復制集的狀態,此時27000為輔助副本

"members" : [
{
"_id" : 0,
"name" : "localhost:27000",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY", // 此節點變成了輔助節點
"uptime" : 28,
"optime" : {
"ts" : Timestamp(1532400746, 1),
"t" : NumberLong(2)
},
"optimeDurable" : {
"ts" : Timestamp(1532400746, 1),
"t" : NumberLong(2)
},

四、獲取復制集的幫助

//獲取副本集相關的幫助命令

repSetTest:SECONDARY> rs.help()
rs.status() { replSetGetStatus : 1 } checks repl set status
rs.initiate() { replSetInitiate : null } initiates set with default settings
rs.initiate(cfg) { replSetInitiate : cfg } initiates set with configuration cfg
rs.conf() get the current configuration object from local.system.replset
rs.reconfig(cfg) updates the configuration of a running replica set with cfg (disconnects)
rs.add(hostportstr) add a new member to the set with default attributes (disconnects)
rs.add(membercfgobj) add a new member to the set with extra attributes (disconnects)
rs.addArb(hostportstr) add a new member which is arbiterOnly:true (disconnects)
rs.stepDown([stepdownSecs, catchUpSecs]) step down as primary (disconnects)
rs.syncFrom(hostportstr) make a secondary sync from the given member
rs.freeze(secs) make a node ineligible to become primary for the time specified
rs.remove(hostportstr) remove a host from the replica set (disconnects)
rs.slaveOk() allow queries on secondary nodes

rs.printReplicationInfo() check oplog size and time range
rs.printSlaveReplicationInfo() check replica set members and replication lag
db.isMaster() check who is primary

reconfiguration helpers disconnect from the database so the shell will display
an error, even if the command succeeds.
repSetTest:SECONDARY>

MongoDB 復制(副本集)