paulwong

          mongodb運維之副本集實踐

          正式環境,
          4臺機器+一臺定時任務的機器。
          服務器是阿里云的ECS,
          負載均衡用的是阿里云的SLB,
          mysql用阿里云的RDS,
          緩存用阿里云的OCS,
          運維基本上是都不需要擔心了,
          現在的云服務已經非常完善了,
          其實我們用阿里云的服務非常多,
          大概有20多個類型的服務,
          感謝阿里云。

          而我的技術棧是nodejs + mongodb,而阿里云有k-v兼容redis協議的nosql,無mongodb,所以就要悲劇的自己運維mongodb了。

          阿里的ots是非結構化存儲,沒有nodejs的sdk,就算有,不兼容mongodb,也沒啥可玩的。

          云服務

          MongoDB存儲服務的云平臺(MongoHQ, MongoLabs 和 Mongo Machine)

          國內的貌似只有 http://developer.baidu.com/wiki/index.php?title=docs/cplat/bae/mongodb

          芋頭推薦用pg,支持json格式存儲

          還有就是parse和leancloud這類面向api的。

          京東和騰訊都有過,后來關閉了,不知何故

          mongodb部署最佳實踐

          常識: replset + shard

          replset是副本集,shard是分片

          mongoDB的主從模式其實就是一個單副本的應用,沒有很好的擴展性和容錯性。而副本集具有多個副本保證了容錯性,就算一個副本掛掉了還有很多副本存在,并且解決了上面第一個問題“主節點掛掉了,整個集群內會自動切換”。

          比如游戲,開了某一個服,那么所有的數據都在一臺服務器上,此時它要保證的是服務不掛就可以,不用考慮更多的并發上的壓力,那么它首先是副本集。

          如果有節點掛了,它會重新選舉新的主節點

          而更多的情況是,你要考慮并發,而且可能是千萬,億萬并發,副本集是搞不定的。

          于是shard就登場了。

          分片并不是mongo獨有的概念,很多數據庫都有,mongodb里的分片是指通過mongos來當網關路由,分發請求到每個shard,然后每個shard會對應各自的副本集。

          既然是分發請求,就會有一定的性能損耗,但好處是你能處理更多請求。所以按照場景選擇

          • 性能最佳,當然是一個副本集,如果能滿足需求,優先
          • 如果副本集不足及支撐并發,那么就選shard

          準備3臺阿里云主機

          • 10.51.83.118
          • 10.51.77.129
          • 10.44.204.241

          先各自ping一下,保證網絡通暢。

          確定我的目標是1主,2從,奇數個

          這篇文字講了Bully算法以及為啥是奇數個

          http://www.lanceyan.com/tech/mongodb_repset2.html

          注意點

          • 服務器節點之前時間要同步
          • 開啟防火墻的一定要允許通過
          • 開啟selinux的也要進行設置
          • 建立雙擊互信模式最好不過

          格式化阿里云的新增硬盤

          http://www.cnblogs.com/dudu/archive/2012/12/07/aliyun-linux-fdisk.html

          然后掛載到/data目錄下

          配置文件

          ~/config/r0.config

          port=27000 
          fork=true
          logpath=/data/replset/log/r0.log
          dbpath=/data/replset/r0
          logappend=true
          replSet=rs
          #keyFile=/data/replset/key/r0

          ~/config/r1.config

          port=27001 
          fork=true
          logpath=/data/replset/log/r1.log
          dbpath=/data/replset/r1
          logappend=true
          replSet=rs
          #keyFile=/data/replset/key/r1

          ~/config/r2.config

          port=27002 
          fork=true
          logpath=/data/replset/log/r2.log
          dbpath=/data/replset/r2
          logappend=true replSet=rs
          #keyFile=/data/replset/key/r2

          啟動

          確保目錄為空,殺死所有mongod進程

          rm -rf /data/replset/  
          ps -ef|grep mongod | awk '{print $2}' | xargs kill -9
          ps -ef|grep mongod

          創建目錄

          mkdir -p /data/replset/r0 
          mkdir -p /data/replset/r1
          mkdir -p /data/replset/r2
          mkdir -p /data/replset/key
          mkdir -p /data/replset/log

          準備key文件

          echo "replset1 key" > /data/replset/key/r0 
          echo "replset1 key" > /data/replset/key/r1
          echo "replset1 key" > /data/replset/key/r2
          chmod 600 /data/replset/key/r*

          注意第一次不能用keyFile

          mongod -f ~/config/r0.config & 
          mongod -f ~/config/r1.config &
          mongod -f ~/config/r2.config &

          配置文件里是fork=true,所以啟動需要點時間

          初始化

          > rs.initiate()   
          {
          "info2" : "no configuration explicitly specified -- making one",
          "me" : "iZ25xk7uei1Z:27001",
          "ok" : 1
          }

          擦,超級慢。。。。

          使用下面語句初始化

          mongo --port 27000 
          rs.initiate({ _id:'rs',members:[{ _id:0, host:'10.51.77.129:27000' }]})

          這個其實也很慢。。。。

          待完成后,繼續增加其他2個節點(一定要注意,在rs:PRIMARY即主節點上才能增加rs:SECONDARY和ARBITER。如果之前連的是其他端口,需要切換的。)

          rs.add("10.51.77.129:27001") 
          rs.addArb("10.51.77.129:27002")

          查看狀態

          rs.status(); 

          如果想移除某一個節點

          rs.remove("10.51.77.129:27001") 
          rs.remove("10.51.77.129:27000")
          rs.remove("10.51.77.129:27002")

          reconfig

          如果想刪除,重置用rs.reconfig(),這樣做不一定會成功,有的時候無法切換到主節點,所以需要,刪除/data/replset目錄,然后重啟所有mongo的進程。

          rs.reconfig({ _id:'rs',members:[{ _id:1, host:'10.51.77.129:27000' }]}) 
          rs.add("10.51.77.129:27000") rs.addArb("10.51.77.129:27002")

          db.oplog.rs

          rs:PRIMARY> use local switched to db local 
          rs:PRIMARY> show collections me oplog.rs startup_log system.indexes system.replset
          rs:PRIMARY>
          rs:PRIMARY>
          rs:PRIMARY> db.oplog.rs.find()
          {
          "ts" : Timestamp(1435495192, 1),
          "h" : NumberLong(0),
          "v" : 2,
          "op" : "n",
          "ns" : "",
          "o" : { "msg" : "initiating set" }
          }

          { "ts" : Timestamp(1435495306, 1),
          "h" : NumberLong(0),
          "v" : 2,
          "op" : "n",
          "ns" : "",
          "o" : { "msg" : "Reconfig set", "version" : 2 }
          }

          { "ts" : Timestamp(1435495323, 1),
          "h" : NumberLong(0),
          "v" : 2,
          "op" : "n",
          "ns" : "",
          "o" : { "msg" : "Reconfig set", "version" : 3 }
          }

          在SECONDARY節點無法show dbs

          主從啟動之后,連接slave可以成功連上,但是在slave中執行 show dbs 的時候就報錯了:

          QUERY    Error: listDatabases failed:{ "note" : "from execCommand", "ok" : 0, "errmsg" : "not master" } 

          解決方法:

          在報錯的slave機器上執行 rs.slaveOk()方法即可。

          解釋一下具體slaveOk方法是什么意思?

          Provides a shorthand for the following operation:  

          db.getMongo().setSlaveOk()
          This allows the current connection to allow read operations to run on secondary members.
          See the readPref() method for more fine-grained control over read preference in the mongo shell.

          see

          內存問題

          查看內存情況最常用的是free命令:

          [deploy@iZ25xk7uei1Z config]$ free -m              
          total used free shared buffers cached
          Mem: 7567 6821 745 8 129 6122
          -/+ buffers/cache: 569 6997
          Swap: 0 0 0

          限制內存

          所有連接消耗的內存加起來會相當驚人,推薦把Stack設置小一點,比如說1024:

          ulimit -s 1024 

          通過調整內核參數drop_caches也可以釋放緩存:

          sysctl vm.drop_caches=1 

          有時候,出于某些原因,你可能想釋放掉MongoDB占用的內存,不過前面說了,內存管理工作是由虛擬內存管理器控制的,幸好可以使用MongoDB內置的closeAllDatabases命令達到目的:

          mongo> use admin 
          mongo> db.runCommand({closeAllDatabases:1})

          平時可以通過mongo命令行來監控MongoDB的內存使用情況,如下所示:

          mongo> db.serverStatus().mem: 
          {
          "resident" : 22346,
          "virtual" : 1938524,
          "mapped" : 962283
          }

          還可以通過mongostat命令來監控MongoDB的內存使用情況,如下所示:

          shell> mongostat 
          mapped vsize res faults
          940g 1893g 21.9g 0

          其中內存相關字段的含義是:

          • mapped:映射到內存的數據大小
          • visze:占用的虛擬內存大小
          • res:占用的物理內存大小

          注:如果操作不能在內存中完成,結果faults列的數值不會是0,視大小可能有性能問題。 在上面的結果中,vsize是mapped的兩倍,而mapped等于數據文件的大小,所以說vsize是數據文件的兩倍,之所以會這樣,是因為本例中,MongoDB開啟了journal,需要在內存里多映射一次數據文件,如果關閉journal,則vsize和mapped大致相當。

          see

          更好的做法是使用docker,一勞永逸

          全文完

          http://my.oschina.net/nodeonly/blog/471834

          歡迎關注我的公眾號【node全棧】

          node全棧.png

          posted on 2015-06-30 10:30 paulwong 閱讀(1892) 評論(0)  編輯  收藏 所屬分類: MONGODB

          主站蜘蛛池模板: 渝北区| 遂川县| 凤山县| 泾阳县| 巴南区| 大兴区| 成武县| 定安县| 舒兰市| 泉州市| 英山县| 西安市| 孟村| 达孜县| 天峻县| 松潘县| 鹤庆县| 马山县| 上高县| 岱山县| 肥乡县| 甘泉县| 罗甸县| 会昌县| 隆德县| 东兰县| 抚宁县| 南木林县| 边坝县| 醴陵市| 昌平区| 郯城县| 通化县| 蓬莱市| 南雄市| 称多县| 博乐市| 迁安市| 陈巴尔虎旗| 沾益县| 昌黎县|