https://gitee.com/et/ops/blob/master/MongoDB副本集配置和數據遷移實戰.mdjavascript
環境:Ubuntu 16.04, MongoDB 3.6java
MongoDB 的副本集就是有自動故障恢復功能的 MongoDB 主從集羣。因爲 MongoDB 的主從複製功能不支持高可用,因此從 3.2 版本開始已經被廢棄了,轉而用副本集來代替。一個副本集總會有一個活躍節點(Primary)和若干個備份節點(Secondary),還有一個可選的一個仲裁者(Arbiter)節點來實現HA中的故障切換。git
參考官方的安裝文檔 https://docs.mongodb.com/manual/tutorial/install-mongodb-on-ubuntu/mongodb
$ mkdir -p /mnt/mongodb/replset
$ mongod --dbpath /mnt/mongodb/replset --port 27017 --replSet "my-repl" --bind_ip_all
$ mongo
> rs.initiate({ _id:"my-repl", members:[ {_id:0, host:"192.168.10.58:27017"}, {_id:1, host:"192.168.10.59:27017"} ] });輸出結果:
{ "ok" : 1, "operationTime" : Timestamp(1523237919, 1), "$clusterTime" : { "clusterTime" : Timestamp(1523237919, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } } }
> rs.conf(); { "_id" : "my-repl", "version" : 1, "protocolVersion" : NumberLong(1), "members" : [ { "_id" : 0, "host" : "192.168.10.58:27017", "arbiterOnly" : false, "buildIndexes" : true, "hidden" : false, "priority" : 1, "tags" : { }, "slaveDelay" : NumberLong(0), "votes" : 1 }, { "_id" : 1, "host" : "192.168.10.59: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("5acac41fded47067da446ddd") } }配置過程很是簡單,能夠看到在副本集成員中有0和1兩個節點,此時主從兩個服務器已經能夠工做了,服務器0(Primary)有任何數據的變化都會同步到服務器1(Secondary)上。可是,此時的副本集只是提供了數據備份的功能,並不能達到高可用。若是要達到這一點,那麼須要配置一個仲裁者節點(Arbiter)
仲裁者在 Primary 節點發生故障時,參與副本集的選舉投票決定哪一個副本成爲 Primary 節點。仲裁節點不保存數據也不會成爲 Primary 節點。ubuntu
仲裁者一般不部署在大磁盤空間的服務器上,所以爲了最小化默認建立數據,修改配置:vim
$ vim /etc/mongod.conf
storage.journal.enabled=false storage.mmapv1.smallFiles = true.
建立仲裁者目錄並啓動服務服務器
$ mkdir /mnt/mongodb/arbiter $ mongod --port 27017 --dbpath /mnt/mongodb/arbiter --replSet 'my-repl' --bind_ip_all
把仲裁者添加到副本集中架構
鏈接至 Primary 服務器app
$mongo --host 192.168.10.58
my-repl:PRIMARY> rs.addArb("192.168.10.57:27017") { "ok" : 1, "operationTime" : Timestamp(1523326877, 1), "$clusterTime" : { "clusterTime" : Timestamp(1523326877, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } } }
查看副本集的效果:ide
>rs.status(); my-repl:PRIMARY> rs.status(); { "set" : "my-repl", "date" : ISODate("2018-04-10T02:21:44.826Z"), "myState" : 1, "term" : NumberLong(2), "heartbeatIntervalMillis" : NumberLong(2000), "optimes" : { "lastCommittedOpTime" : { "ts" : Timestamp(1523326895, 1), "t" : NumberLong(2) }, "readConcernMajorityOpTime" : { "ts" : Timestamp(1523326895, 1), "t" : NumberLong(2) }, "appliedOpTime" : { "ts" : Timestamp(1523326895, 1), "t" : NumberLong(2) }, "durableOpTime" : { "ts" : Timestamp(1523326895, 1), "t" : NumberLong(2) } }, "members" : [ { "_id" : 0, "name" : "192.168.10.58:27017", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 2891, "optime" : { "ts" : Timestamp(1523326895, 1), "t" : NumberLong(2) }, "optimeDate" : ISODate("2018-04-10T02:21:35Z"), "electionTime" : Timestamp(1523324284, 1), "electionDate" : ISODate("2018-04-10T01:38:04Z"), "configVersion" : 2, "self" : true }, { "_id" : 1, "name" : "192.168.10.59:27017", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 2624, "optime" : { "ts" : Timestamp(1523326895, 1), "t" : NumberLong(2) }, "optimeDurable" : { "ts" : Timestamp(1523326895, 1), "t" : NumberLong(2) }, "optimeDate" : ISODate("2018-04-10T02:21:35Z"), "optimeDurableDate" : ISODate("2018-04-10T02:21:35Z"), "lastHeartbeat" : ISODate("2018-04-10T02:21:43.080Z"), "lastHeartbeatRecv" : ISODate("2018-04-10T02:21:43.083Z"), "pingMs" : NumberLong(0), "syncingTo" : "192.168.10.58:27017", "configVersion" : 2 }, { "_id" : 2, "name" : "192.168.10.57:27017", "health" : 1, "state" : 7, "stateStr" : "ARBITER", "uptime" : 27, "lastHeartbeat" : ISODate("2018-04-10T02:21:43.079Z"), "lastHeartbeatRecv" : ISODate("2018-04-10T02:21:42.088Z"), "pingMs" : NumberLong(0), "configVersion" : 2 } ], "ok" : 1, "operationTime" : Timestamp(1523326895, 1), "$clusterTime" : { "clusterTime" : Timestamp(1523326895, 1), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } } }
能夠看到狀態顯示:服務器0爲 Primary, 服務器1爲 Secondary, 服務器2爲 Arbiter。
此時帶有高可用的副本集已經配置完成,Arbiter 會監控 Primary 節點的運行狀況,若是服務器0發生了宕機,那麼仲裁者 Arbiter 節點會發起選舉,最終選取多個 Secondary 中的某一個來做爲 Primary 節點。咱們測試的架構中只有一個 Secondary 節點,那麼此服務器1就會成爲 Primary。而當服務器0恢復工做時,它會被當成 Secondary 來運行。
副本優先級
副本集會在 Primary 節點出現故障時把 Secondary 提高爲 Primary,可是不少狀況下 Secondary 只是做爲備用節點,咱們不但願它長期做爲 Primary 節點運行。那麼爲了達到這個目的,咱們修改副本的優先級。
cfg = rs.conf() cfg.members[0].priority = 10 cfg.members[1].priority = 5 rs.reconfig(cfg) { "ok" : 1, "operationTime" : Timestamp(1523411797, 2), "$clusterTime" : { "clusterTime" : Timestamp(1523411797, 2), "signature" : { "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="), "keyId" : NumberLong(0) } } }
{ "ok" : 0, "errmsg" : "replSetReconfig should only be run on PRIMARY, but my state is ARBITER; use the \"force\" argument to override", "code" : 10107, "codeName" : "NotMaster" }
在配置副本集以前,你可能已經存在了一個單獨的 MongoDB 實例存儲了一些數據,你須要把原來實例中的數據遷移到新的副本集中。(你也能夠一開始就把原來的單個實例配置成副本集的 Primary 節點,而後新增副原本同步數據,此方法不在本文討論範圍以內)
登陸原實例所在的服務器,導出數據:
$ mongoexport -h localhost -p 27017 -u xxx -p xxx -d MY_DB_NAME -c MY_COLLECTION_NAME -o MY_COLLECTION_NAME.dmp
在阿里雲上測試了一個導出數據大約爲1.2G大小的集合,導出性能以下:
將導出的數據文件 MY_COLLECTION_NAME.dmp 已任何方式(好比scp)同步到 Primary 節點所在的服務器0上
導入數據至副本集 Primay 節點
mongoimport -h my-repl/192.168.10.58:27017 -d MY_DB_NAME -c MY_COLLECTION_NAME --file MY_COLLECTION_NAME.dmp
測試導入性能
注意:因爲不是相同的服務器,因此不能經過這個來比較導入和導出的性能差異,只能所謂一個參考:
總結: