複製集原理
複製集的作用
主要為了實現mongodb
服務的高可用,複製集之間是一種主從關係
- 當資料寫入時將資料迅速複製到其它節點
- 當主節點發生故障時自動選出一個新的節點代替
由上面的特點,我們對redis
瞭解的話,可以很快聯想到哨兵模式
在除了以上的資料同步
和故障節點替換
兩大特性以外,複製集還存在以下作用
資料分發:將資料分發到不同的區域,減少讀的延遲
例如公司在北京、上海、廣州都有資料中心,但只有北京的是可以寫入的中心,可將資料異地分發,提高上海和廣州大區使用者的讀取效率。
- 讀寫分離
- 異地容災:資料中心故障時快速切換到異地。
複製集的結構
複製集的結構與其它中介軟體的主從模式基本類似。
一個典型的複製集由3個及以上具有投票的節點組成:
- 主節點:只有一個,負責資料的寫入和讀取,以及選舉時投票。
- 從節點:至少有兩個,負責資料讀取和選舉投票。
資料的複製原理
- 當資料(主節點)發生修改(增刪改)時,它對資料的操作將被記錄在一個
oplog
檔案當中。 - 從節點通過在主節點上代開一個
tailable
遊標不斷獲取主節點中新增的oplog
並且不斷在自己的節點上重現這些操作,以此來實現和主節點上的資料一致。
主節點選舉原理
- 具有投票權的節點之間兩兩互相傳送心跳。
- 當5次心跳未收到時判斷為節點失聯。
- 如果主節點失聯,從節點會選出新的主節點,但失聯的從節點不會參與選舉。
- 選舉基於RAFT一致性演算法實現,選舉成功的必要條件是大多數投票節點存活。
- 複製集中最多可有50個節點,但有投票權的最多有7個。
- 被選舉為主節點的的節點 必須能與多數節點建立連線、有比較新的
oplog
、比較高的優先順序(如果配置中有)
搭建一個複製集
下面是在linux
下建立一個mongodb
複製集
建立三個目錄
mkdir -p /data/mongodb/db{1,2,3}
配置檔案
#節點1
systemLog:
destination: file
path: /data/mongodb/db1/mongod.log #日誌路徑
logAppend: true
storage:
dbPath: /data/mongodb/db1 #資料檔案
net:
bindIp: 0.0.0.0 #在所有網路卡監聽,為了外網訪問
port: 28017
replication: #複製集,沒有的話就是一個單節點
replSetName: rs0 #複製集名字
processManagement:
fork: true #把程式作為獨立的後臺程式程式
#節點2
systemLog:
destination: file
path: /data/mongodb/db2/mongod.log #日誌路徑
logAppend: true
storage:
dbPath: /data/mongodb/db2 #資料檔案
net:
bindIp: 0.0.0.0 #在所有網路卡監聽,為了外網訪問
port: 28018
replication: #複製集,沒有的話就是一個單節點
replSetName: rs0 #複製集名字
processManagement:
fork: true #把程式作為獨立的後臺程式程式
#節點3
systemLog:
destination: file
path: /data/mongodb/db3/mongod.log #日誌路徑
logAppend: true
storage:
dbPath: /data/mongodb/db3 #資料檔案
net:
bindIp: 0.0.0.0 #在所有網路卡監聽,為了外網訪問
port: 28019
replication: #複製集,沒有的話就是一個單節點
replSetName: rs0 #複製集名字
processManagement:
fork: true #把程式作為獨立的後臺程式程式
啟動程式
mongod -f db1/mongod.conf
mongod -f db2/mongod.conf
mongod -f db3/mongod.conf
配置複製集
進入主節點
mongo --port 28017
設定主節點
rs.initiate()
{ "info2" : "no configuration specified. Using a default configuration for the set", "me" : "supman:28017", "ok" : 1 }
檢視節點狀態
rs.status()
{ "set" : "rs0", "date" : ISODate("2021-11-30T15:33:30.616Z"), "myState" : 1, "term" : NumberLong(1), "syncSourceHost" : "", "syncSourceId" : -1, "heartbeatIntervalMillis" : NumberLong(2000), "majorityVoteCount" : 1, "writeMajorityCount" : 1, "votingMembersCount" : 1, "writableVotingMembersCount" : 1, "optimes" : { "lastCommittedOpTime" : { "ts" : Timestamp(1638286404, 1), "t" : NumberLong(1) }, "lastCommittedWallTime" : ISODate("2021-11-30T15:33:24.656Z"), "readConcernMajorityOpTime" : { "ts" : Timestamp(1638286404, 1), "t" : NumberLong(1) }, "readConcernMajorityWallTime" : ISODate("2021-11-30T15:33:24.656Z"), "appliedOpTime" : { "ts" : Timestamp(1638286404, 1), "t" : NumberLong(1) }, "durableOpTime" : { "ts" : Timestamp(1638286404, 1), "t" : NumberLong(1) }, "lastAppliedWallTime" : ISODate("2021-11-30T15:33:24.656Z"), "lastDurableWallTime" : ISODate("2021-11-30T15:33:24.656Z") }, "lastStableRecoveryTimestamp" : Timestamp(1638286364, 1), "electionCandidateMetrics" : { "lastElectionReason" : "electionTimeout", "lastElectionDate" : ISODate("2021-11-30T15:27:54.614Z"), "electionTerm" : NumberLong(1), "lastCommittedOpTimeAtElection" : { "ts" : Timestamp(0, 0), "t" : NumberLong(-1) }, "lastSeenOpTimeAtElection" : { "ts" : Timestamp(1638286074, 1), "t" : NumberLong(-1) }, "numVotesNeeded" : 1, "priorityAtElection" : 1, "electionTimeoutMillis" : NumberLong(10000), "newTermStartDate" : ISODate("2021-11-30T15:27:54.637Z"), "wMajorityWriteAvailabilityDate" : ISODate("2021-11-30T15:27:54.660Z") }, "members" : [ { "_id" : 0, "name" : "supman:28017", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 1227, "optime" : { "ts" : Timestamp(1638286404, 1), "t" : NumberLong(1) }, "optimeDate" : ISODate("2021-11-30T15:33:24Z"), "syncSourceHost" : "", "syncSourceId" : -1, "infoMessage" : "", "electionTime" : Timestamp(1638286074, 2), "electionDate" : ISODate("2021-11-30T15:27:54Z"), "configVersion" : 1, "configTerm" : 1, "self" : true, "lastHeartbeatMessage" : "" } ], "ok" : 1, "$clusterTime" : { "clusterTime" : Timestamp(1638286404, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } }, "operationTime" : Timestamp(1638286404, 1) }
找到status資訊裡面的
members.name
欄位"name" : "supman:28017"
增加從節點
rs.add("supman:28018")
{ "ok" : 1, "$clusterTime" : { "clusterTime" : Timestamp(1638286626, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } }, "operationTime" : Timestamp(1638286626, 1) }
rs.add("supman:28019")
{ "ok" : 1, "$clusterTime" : { "clusterTime" : Timestamp(1638286660, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } }, "operationTime" : Timestamp(1638286660, 1) }
再次檢視狀態
{ "set" : "rs0", "date" : ISODate("2021-11-30T15:44:29.903Z"), "myState" : 1, "term" : NumberLong(1), "syncSourceHost" : "", "syncSourceId" : -1, "heartbeatIntervalMillis" : NumberLong(2000), "majorityVoteCount" : 2, "writeMajorityCount" : 2, "votingMembersCount" : 3, "writableVotingMembersCount" : 3, "optimes" : { "lastCommittedOpTime" : { "ts" : Timestamp(1638287064, 1), "t" : NumberLong(1) }, "lastCommittedWallTime" : ISODate("2021-11-30T15:44:24.673Z"), "readConcernMajorityOpTime" : { "ts" : Timestamp(1638287064, 1), "t" : NumberLong(1) }, "readConcernMajorityWallTime" : ISODate("2021-11-30T15:44:24.673Z"), "appliedOpTime" : { "ts" : Timestamp(1638287064, 1), "t" : NumberLong(1) }, "durableOpTime" : { "ts" : Timestamp(1638287064, 1), "t" : NumberLong(1) }, "lastAppliedWallTime" : ISODate("2021-11-30T15:44:24.673Z"), "lastDurableWallTime" : ISODate("2021-11-30T15:44:24.673Z") }, "lastStableRecoveryTimestamp" : Timestamp(1638287034, 1), "electionCandidateMetrics" : { "lastElectionReason" : "electionTimeout", "lastElectionDate" : ISODate("2021-11-30T15:27:54.614Z"), "electionTerm" : NumberLong(1), "lastCommittedOpTimeAtElection" : { "ts" : Timestamp(0, 0), "t" : NumberLong(-1) }, "lastSeenOpTimeAtElection" : { "ts" : Timestamp(1638286074, 1), "t" : NumberLong(-1) }, "numVotesNeeded" : 1, "priorityAtElection" : 1, "electionTimeoutMillis" : NumberLong(10000), "newTermStartDate" : ISODate("2021-11-30T15:27:54.637Z"), "wMajorityWriteAvailabilityDate" : ISODate("2021-11-30T15:27:54.660Z") }, "members" : [ { "_id" : 0, "name" : "supman:28017", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 1886, "optime" : { "ts" : Timestamp(1638287064, 1), "t" : NumberLong(1) }, "optimeDate" : ISODate("2021-11-30T15:44:24Z"), "syncSourceHost" : "", "syncSourceId" : -1, "infoMessage" : "", "electionTime" : Timestamp(1638286074, 2), "electionDate" : ISODate("2021-11-30T15:27:54Z"), "configVersion" : 3, "configTerm" : 1, "self" : true, "lastHeartbeatMessage" : "" }, { "_id" : 1, "name" : "supman:28018", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 442, "optime" : { "ts" : Timestamp(1638287064, 1), "t" : NumberLong(1) }, "optimeDurable" : { "ts" : Timestamp(1638287064, 1), "t" : NumberLong(1) }, "optimeDate" : ISODate("2021-11-30T15:44:24Z"), "optimeDurableDate" : ISODate("2021-11-30T15:44:24Z"), "lastHeartbeat" : ISODate("2021-11-30T15:44:28.545Z"), "lastHeartbeatRecv" : ISODate("2021-11-30T15:44:28.566Z"), "pingMs" : NumberLong(0), "lastHeartbeatMessage" : "", "syncSourceHost" : "supman:28017", "syncSourceId" : 0, "infoMessage" : "", "configVersion" : 3, "configTerm" : 1 }, { "_id" : 2, "name" : "supman:28019", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 409, "optime" : { "ts" : Timestamp(1638287064, 1), "t" : NumberLong(1) }, "optimeDurable" : { "ts" : Timestamp(1638287064, 1), "t" : NumberLong(1) }, "optimeDate" : ISODate("2021-11-30T15:44:24Z"), "optimeDurableDate" : ISODate("2021-11-30T15:44:24Z"), "lastHeartbeat" : ISODate("2021-11-30T15:44:28.565Z"), "lastHeartbeatRecv" : ISODate("2021-11-30T15:44:29.316Z"), "pingMs" : NumberLong(0), "lastHeartbeatMessage" : "", "syncSourceHost" : "supman:28018", "syncSourceId" : 1, "infoMessage" : "", "configVersion" : 3, "configTerm" : 1 } ], "ok" : 1, "$clusterTime" : { "clusterTime" : Timestamp(1638287064, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } }, "operationTime" : Timestamp(1638287064, 1) }
在從節點上配置可讀
進入從節點
mongo --port 28018
mongo --port 28019
設定從節點可讀
rs.slaveOk()
- 最後在主節點增加一個使用者,建立一個資料庫和集合,插入資料後也能在從節點檢視到資料了