MongoDB學習之複製集

小勇勇 發表於 2021-12-08
MongoDB

複製集原理

複製集的作用

主要為了實現mongodb服務的高可用,複製集之間是一種主從關係

  • 當資料寫入時將資料迅速複製到其它節點
  • 當主節點發生故障時自動選出一個新的節點代替

由上面的特點,我們對redis瞭解的話,可以很快聯想到哨兵模式

在除了以上的資料同步故障節點替換兩大特性以外,複製集還存在以下作用

  • 資料分發:將資料分發到不同的區域,減少讀的延遲

    例如公司在北京、上海、廣州都有資料中心,但只有北京的是可以寫入的中心,可將資料異地分發,提高上海和廣州大區使用者的讀取效率。

  • 讀寫分離
  • 異地容災:資料中心故障時快速切換到異地。

複製集的結構

複製集的結構與其它中介軟體的主從模式基本類似。

一個典型的複製集由3個及以上具有投票的節點組成:

  • 主節點:只有一個,負責資料的寫入和讀取,以及選舉時投票。
  • 從節點:至少有兩個,負責資料讀取和選舉投票。

資料的複製原理

  • 當資料(主節點)發生修改(增刪改)時,它對資料的操作將被記錄在一個oplog檔案當中。
  • 從節點通過在主節點上代開一個tailable遊標不斷獲取主節點中新增的oplog並且不斷在自己的節點上重現這些操作,以此來實現和主節點上的資料一致。

主節點選舉原理

  1. 具有投票權的節點之間兩兩互相傳送心跳。
  2. 當5次心跳未收到時判斷為節點失聯。
  3. 如果主節點失聯,從節點會選出新的主節點,但失聯的從節點不會參與選舉。
  4. 選舉基於RAFT一致性演算法實現,選舉成功的必要條件是大多數投票節點存活。
  5. 複製集中最多可有50個節點,但有投票權的最多有7個。
  6. 被選舉為主節點的的節點 必須能與多數節點建立連線、有比較新的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
配置複製集
  1. 進入主節點

    mongo --port 28017

  2. 設定主節點

    rs.initiate()

    {
            "info2" : "no configuration specified. Using a default configuration for the set",
            "me" : "supman:28017",
            "ok" : 1
    }
  3. 檢視節點狀態

    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"
  4. 增加從節點

    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)
    }
  5. 再次檢視狀態

    {
            "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)
    }
  6. 在從節點上配置可讀

    進入從節點

    mongo --port 28018 mongo --port 28019

    設定從節點可讀

    rs.slaveOk()

  7. 最後在主節點增加一個使用者,建立一個資料庫和集合,插入資料後也能在從節點檢視到資料了