下圖顯示了應用程序查詢三節點副本集的典型環境。node
在正常操做期間,副本集只有一個節點做爲PRIMARY而全部其餘節點都是SECONDARY。PRIMARY成員是惟一接收寫入的成員。它更新其本地集合和文檔以及oplog。而後,oplog事件經過複製通道發送到全部SECONDARY節點。每一個SECONDARY節點在本地和異步上應用對本地數據和oplog的相同修改。算法
下圖在內部顯示了副本集的工做原理。每一個節點都鏈接到全部其餘節點,而且有一個心跳機制來ping任何其餘節點。心跳具備用於ping節點的可配置時間,默認值爲10秒。sql
若是全部節點都響應心跳確認,則羣集繼續工做。若是其中一個節點崩潰,例如PRIMARY(最壞的狀況),則發生涉及剩餘節點的選舉。mongodb
當SECONDARY在配置的超時後沒有收到對心跳的響應時,它會要求進行選舉。仍然存活的節點投票支持新的PRIMARY。選舉階段一般不須要很長時間,選舉算法足夠複雜,讓他們選擇最佳的次要成爲新的主要。讓咱們說這是次要的,與死亡的初級主要是最新的。shell
除了主要崩潰以外,還有一些節點要求進行選舉的狀況:將節點添加到副本集時,在「啓動副本集」期間或在某些維護活動期間。這種選舉不是本文的目的。數據庫
副本集在選舉成功完成以前沒法處理寫入操做,但若是將此類查詢配置爲在輔助節點上運行,則能夠繼續提供讀取查詢(稍後咱們將對此進行討論)。選舉正確完成後,羣集將恢復正常操做。bash
要正常工做,副本集須要具備奇數個成員。在網絡分裂的狀況下,只有奇數個成員確保咱們在其中一個子集中擁有大多數投票。在具備大多數節點的子集中選擇新的PRIMARY。服務器
所以,三個是副本集的最小節點數,以確保高可用性。網絡
因爲每一個節點都須要擁有完整的數據副本,所以若是您擁有龐大的數據庫,則須要提供至少三臺具備大量磁盤,內存和CPU資源的計算機。這可能很昂貴。app
幸運的是,您能夠將其中一個節點配置爲Arbiter,這是一個不復制數據的特殊成員。它是空的,但它能夠在選舉期間投票。
使用仲裁節點是維持奇數成員的一個很好的解決方案,而不須要花費不少錢來使第三個節點像其餘節點同樣強大。仲裁節點不能被選爲新主節點,由於它沒有數據。
ip | 主機名 | 系統 |
---|---|---|
172.18.11.142 | nodejs1 | Centos 7.6 |
172.18.11.143 | nodejs2 | Centos 7.6 |
172.18.11.144 | nodejs3 | Centos 7.6 |
# 下載安裝包並安裝 mkdir -p /opt/mongodb/ cat <<EOF > /opt/mongodb/mongodb_down.sh cd /opt/mongodb/ wget https://www.percona.com/downloads/percona-server-mongodb-LATEST/percona-server-mongodb-4.0.9-4/binary/redhat/7/x86_64/percona-server-mongodb-shell-4.0.9-4.el7.x86_64.rpm wget https://www.percona.com/downloads/percona-server-mongodb-LATEST/percona-server-mongodb-4.0.9-4/binary/redhat/7/x86_64/percona-server-mongodb-mongos-4.0.9-4.el7.x86_64.rpm wget https://www.percona.com/downloads/percona-server-mongodb-LATEST/percona-server-mongodb-4.0.9-4/binary/redhat/7/x86_64/percona-server-mongodb-tools-4.0.9-4.el7.x86_64.rpm wget https://www.percona.com/downloads/percona-server-mongodb-LATEST/percona-server-mongodb-4.0.9-4/binary/redhat/7/x86_64/percona-server-mongodb-server-4.0.9-4.el7.x86_64.rpm wget https://www.percona.com/downloads/percona-server-mongodb-LATEST/percona-server-mongodb-4.0.9-4/binary/redhat/7/x86_64/percona-server-mongodb-4.0.9-4.el7.x86_64.rpm EOF bash -x /opt/mongodb/mongodb_down.sh yum localinstall /opt/mongodb/*.rpm -y systemctl enable mongod
主機名
cat <<EOF >> /etc/hosts 192.168.0.249 k8s-m1 192.168.0.250 k8s-n1 192.168.0.251 k8s-n2 EOF
配置文件
cat <<EOF > /etc/mongod.conf storage: dbPath: /var/lib/mongo journal: enabled: true systemLog: destination: file logAppend: true path: /var/log/mongo/mongod.log processManagement: fork: true pidFilePath: /var/run/mongod.pid net: port: 27017 bindIp: 0.0.0.0 EOF
啓動
systemctl start mongod
副本集的名稱
副本集的名稱這裏使用 rs-smy,將副本集名稱放置於每一臺主機的 /etc/mongod.conf
replication: replSetName: "rs-smy"
重啓全部服務器
systemctl restart mongod
初始化集羣
隨便鏈接到一個節點,發出 rs.initiate() 讓副本集直到有哪些成員
rs.initiate( { _id: "rs-smy", members: [ { _id: 0, host: "172.18.11.142:27017" }, { _id: 1, host: "172.18.11.143:27017" }, { _id: 2, host: "172.18.11.144:27017" } ] })
發出命令後,MongoDB使用默認配置啓動複製過程。選擇PRIMARY節點,如今將建立的全部文檔將在SECONDARY節點上異步複製。
咱們能夠經過查看mongo shell提示符來驗證複製是否正常。一旦副本集啓動並運行,提示應該在PRIMARY節點上以下:
rs-smy:PRIMARY>
在SECONDARY節點上這樣:
rs-test:SECONDARY>
有幾個命令能夠調查並在副本集上執行一些管理任務。這裏有幾個。
要調查副本集配置,您能夠在任何節點上發出rs.conf()
rs-smy:SECONDARY> rs.conf() { "_id" : "rs-smy", "version" : 1, "protocolVersion" : NumberLong(1), "writeConcernMajorityJournalDefault" : true, "members" : [ { "_id" : 0, "host" : "172.18.11.142:27017", "arbiterOnly" : false, "buildIndexes" : true, "hidden" : false, "priority" : 1, "tags" : { }, "slaveDelay" : NumberLong(0), "votes" : 1 }, { "_id" : 1, "host" : "172.18.11.143:27017", "arbiterOnly" : false, "buildIndexes" : true, "hidden" : false, "priority" : 1, "tags" : { }, "slaveDelay" : NumberLong(0), "votes" : 1 }, { "_id" : 2, "host" : "172.18.11.144: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("5ce54845de4f73c1e97ea042") } }
咱們能夠看到有關已配置節點的信息,不管是仲裁仍是隱藏,優先級以及有關心跳過程的其餘詳細信息。
要調查副本集狀態,您能夠在任何節點上發出rs.status()
s-smy:SECONDARY> rs.status() { "set" : "rs-smy", "date" : ISODate("2019-05-23T10:12:44.663Z"), "myState" : 2, "term" : NumberLong(7), "syncingTo" : "172.18.11.144:27017", "syncSourceHost" : "172.18.11.144:27017", "syncSourceId" : 2, "heartbeatIntervalMillis" : NumberLong(2000), "optimes" : { "lastCommittedOpTime" : { "ts" : Timestamp(1558606360, 1), "t" : NumberLong(7) }, "readConcernMajorityOpTime" : { "ts" : Timestamp(1558606360, 1), "t" : NumberLong(7) }, "appliedOpTime" : { "ts" : Timestamp(1558606360, 1), "t" : NumberLong(7) }, "durableOpTime" : { "ts" : Timestamp(1558606360, 1), "t" : NumberLong(7) } }, "lastStableCheckpointTimestamp" : Timestamp(1558606350, 1), "members" : [ { "_id" : 0, "name" : "172.18.11.142:27017", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 24733, "optime" : { "ts" : Timestamp(1558606360, 1), "t" : NumberLong(7) }, "optimeDate" : ISODate("2019-05-23T10:12:40Z"), "syncingTo" : "172.18.11.144:27017", "syncSourceHost" : "172.18.11.144:27017", "syncSourceId" : 2, "infoMessage" : "", "configVersion" : 1, "self" : true, "lastHeartbeatMessage" : "" }, { "_id" : 1, "name" : "172.18.11.143:27017", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 24523, "optime" : { "ts" : Timestamp(1558606360, 1), "t" : NumberLong(7) }, "optimeDurable" : { "ts" : Timestamp(1558606360, 1), "t" : NumberLong(7) }, "optimeDate" : ISODate("2019-05-23T10:12:40Z"), "optimeDurableDate" : ISODate("2019-05-23T10:12:40Z"), "lastHeartbeat" : ISODate("2019-05-23T10:12:44.463Z"), "lastHeartbeatRecv" : ISODate("2019-05-23T10:12:44.448Z"), "pingMs" : NumberLong(0), "lastHeartbeatMessage" : "", "syncingTo" : "172.18.11.144:27017", "syncSourceHost" : "172.18.11.144:27017", "syncSourceId" : 2, "infoMessage" : "", "configVersion" : 1 }, { "_id" : 2, "name" : "172.18.11.144:27017", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 24519, "optime" : { "ts" : Timestamp(1558606360, 1), "t" : NumberLong(7) }, "optimeDurable" : { "ts" : Timestamp(1558606360, 1), "t" : NumberLong(7) }, "optimeDate" : ISODate("2019-05-23T10:12:40Z"), "optimeDurableDate" : ISODate("2019-05-23T10:12:40Z"), "lastHeartbeat" : ISODate("2019-05-23T10:12:44.464Z"), "lastHeartbeatRecv" : ISODate("2019-05-23T10:12:44.433Z"), "pingMs" : NumberLong(0), "lastHeartbeatMessage" : "", "syncingTo" : "", "syncSourceHost" : "", "syncSourceId" : -1, "infoMessage" : "", "electionTime" : Timestamp(1558594808, 1), "electionDate" : ISODate("2019-05-23T07:00:08Z"), "configVersion" : 1 } ], "ok" : 1, "operationTime" : Timestamp(1558606360, 1), "$clusterTime" : { "clusterTime" : Timestamp(1558606360, 1), "signature" : { "hash" : BinData(0,"eo6zfAdAzzCTw/rQj+OWbd7Vots="), "keyId" : NumberLong("6693835933885661186") } } }
能夠看到哪一個是PRIMARY,哪一個是SECONDARY
鏈接到PRIMARY節點並建立例子:
rs-smy:PRIMARY> use test switched to db test rs-test:PRIMARY> db.foo.insert( {name:"Bruce", surname:"Dickinson"} ) WriteResult({ "nInserted" : 1 }) rs-smy:PRIMARY> db.foo.find().pretty() { "_id" : ObjectId("5ae05ac27e6680071caf94b7") "name" : "Bruce" "surname" : "Dickinson" }
而後鏈接到SECONDARY節點並查找相同的文檔。
請記住,您沒法鏈接到SECONDARY節點以讀取數據。默認狀況下,只容許在PRIMARY上進行讀寫操做。所以,若是要讀取SECONDARY節點上的數據,首先須要發出rs.slaveOK()命令。若是您不這樣作,您將收到錯誤。
rs-test:SECONDARY> rs.slaveOK() rs-test:SECONDARY> show collections local <strong>foo</strong> rs-test:SECONDARY> db.foo.find().pretty() { "_id" : ObjectId("5ae05ac27e6680071caf94b7") "name" : "Bruce" "surname" : "Dickinson" }
SECONDARY節點已經複製了集合foo和插入文檔的建立。