MongoDB副本集配置和數據遷移實戰

MongoDB副本集配置和數據遷移實戰

https://gitee.com/et/ops/blob/master/MongoDB副本集配置和數據遷移實戰.md

環境:Ubuntu 16.04, MongoDB 3.6

基本概念

MongoDB 的副本集就是有自動故障恢復功能的 MongoDB 主從集群。由於 MongoDB 的主從複製功能不支持高可用,所以從 3.2 版本開始已經被廢棄了,轉而用副本集來代替。一個副本集總會有一個活躍節點(Primary)和若干個備份節點(Secondary),還有一個可選的一個仲裁者(Arbiter)節點來實現HA中的故障切換。

準備工作

  • 準備三臺服務器(虛擬機亦可),系統全部安裝Ubuntu 16.04 例如:
  • Primary 192.168.10.58
  • Secondary 192.168.10.59
  • Arbiter 192.168.10.57
  • 三臺服務器上都安裝好 MongoDB 3.6

參考官方的安裝文檔 https://docs.mongodb.com/manual/tutorial/install-mongodb-on-ubuntu/

配置副本集 Primary 和 Secondary 節點

  • 創建數據目錄
$ mkdir -p /mnt/mongodb/replset
  • 啟動名為“my-repl”的副本集,端口為27017,綁定到任意IP(也可以指定IP)
$ mongod --dbpath /mnt/mongodb/replset --port 27017 --replSet "my-repl" --bind_ip_all
  • 初始化副本集
  • 用mongo客戶端連接 Primary 節點:
$ 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)

配置仲裁者(Arbiter)

仲裁者在 Primary 節點發生故障時,參與副本集的選舉投票決定哪個副本成為 Primary 節點。仲裁節點不保存數據也不會成為 Primary 節點。

  • 仲裁者通常不部署在大磁盤空間的服務器上,因此為了最小化默認創建數據,修改配置:
$ vim /etc/mongod.confstorage.journal.enabled=falsestorage.mmapv1.smallFiles = true.
  • 創建仲裁者目錄並啟動服務
$ mkdir /mnt/mongodb/arbiter$ mongod --port 27017 --dbpath /mnt/mongodb/arbiter --replSet 'my-repl' --bind_ip_all
  • 把仲裁者添加到副本集中
  • 連接至 Primary 服務器
$mongo --host 192.168.10.58my-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)}}}
  • 查看副本集的效果:
>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 節點運行。那麼為了達到這個目的,我們修改副本的優先級。
  • 連接 Primary 節點,執行以下腳本:
cfg = rs.conf()cfg.members[0].priority = 10cfg.members[1].priority = 5rs.reconfig(cfg){"ok" : 1,"operationTime" : Timestamp(1523411797, 2),"$clusterTime" : {"clusterTime" : Timestamp(1523411797, 2),"signature" : {"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),"keyId" : NumberLong(0)}}}
  • 如果在非 Prmiary 上比如Arbiter上運行,會報下面的錯誤:
{ "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"}
  • 以上操作讓服務器0的優先級高於服務器1,那麼當服務器0從故障中恢復時,它會重新成為 Primary 節點來提供服務。

數據遷移

在配置副本集之前,你可能已經存在了一個單獨的 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大小的集合,導出性能如下:
  • 時間:3分11秒
  • 導出1728423條記錄,每秒讀取記錄數=1728423/191=9050條/秒
  • 導出1264441038字節,每秒處理字節數=1264441038/191=6.6M/秒
  • 將導出的數據文件 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
  • 測試導入性能
  • 時間:82秒
  • 導入1728423條記錄,每秒寫入記錄數=1728423/82=21078條/秒
  • 導入1264441038字節,每秒處理字節數=1264441038/82=14.7M/秒

注意:由於不是相同的服務器,所以不能通過這個來比較導入和導出的性能差別,只能所謂一個參考:

  • 總結:
  • 在 Primary 節點導入數據後,登錄 Secondary 節點查看,可以看到一百七十多萬條數據全部複製過去了,主從複製成功。
  • 從性能分析結果來看,MongoDB的讀取和寫入性能是比較好的,特別是導入的同時還要和副本之間同步數據。


分享到:


相關文章: