mongodb運(yùn)維之副本集實踐
正式環(huán)境,
4臺機(jī)器+一臺定時任務(wù)的機(jī)器。
服務(wù)器是阿里云的ECS,
負(fù)載均衡用的是阿里云的SLB,
mysql用阿里云的RDS,
緩存用阿里云的OCS,
運(yùn)維基本上是都不需要擔(dān)心了,
現(xiàn)在的云服務(wù)已經(jīng)非常完善了,
其實我們用阿里云的服務(wù)非常多,
大概有20多個類型的服務(wù),
感謝阿里云。
而我的技術(shù)棧是nodejs + mongodb,而阿里云有k-v兼容redis協(xié)議的nosql,無mongodb,所以就要悲劇的自己運(yùn)維mongodb了。
阿里的ots是非結(jié)構(gòu)化存儲,沒有nodejs的sdk,就算有,不兼容mongodb,也沒啥可玩的。
云服務(wù)
MongoDB存儲服務(wù)的云平臺(MongoHQ, MongoLabs 和 Mongo Machine)
國內(nèi)的貌似只有 http://developer.baidu.com/wiki/index.php?title=docs/cplat/bae/mongodb
芋頭推薦用pg,支持json格式存儲
還有就是parse和leancloud這類面向api的。
京東和騰訊都有過,后來關(guān)閉了,不知何故
mongodb部署最佳實踐
常識: replset + shard
replset是副本集,shard是分片
mongoDB的主從模式其實就是一個單副本的應(yīng)用,沒有很好的擴(kuò)展性和容錯性。而副本集具有多個副本保證了容錯性,就算一個副本掛掉了還有很多副本存在,并且解決了上面第一個問題“主節(jié)點(diǎn)掛掉了,整個集群內(nèi)會自動切換”。
比如游戲,開了某一個服,那么所有的數(shù)據(jù)都在一臺服務(wù)器上,此時它要保證的是服務(wù)不掛就可以,不用考慮更多的并發(fā)上的壓力,那么它首先是副本集。
如果有節(jié)點(diǎn)掛了,它會重新選舉新的主節(jié)點(diǎn)
而更多的情況是,你要考慮并發(fā),而且可能是千萬,億萬并發(fā),副本集是搞不定的。
于是shard就登場了。
分片并不是mongo獨(dú)有的概念,很多數(shù)據(jù)庫都有,mongodb里的分片是指通過mongos來當(dāng)網(wǎng)關(guān)路由,分發(fā)請求到每個shard,然后每個shard會對應(yīng)各自的副本集。
既然是分發(fā)請求,就會有一定的性能損耗,但好處是你能處理更多請求。所以按照場景選擇
- 性能最佳,當(dāng)然是一個副本集,如果能滿足需求,優(yōu)先
- 如果副本集不足及支撐并發(fā),那么就選shard
準(zhǔn)備3臺阿里云主機(jī)
- 10.51.83.118
- 10.51.77.129
- 10.44.204.241
先各自ping一下,保證網(wǎng)絡(luò)通暢。
確定我的目標(biāo)是1主,2從,奇數(shù)個
這篇文字講了Bully算法以及為啥是奇數(shù)個
http://www.lanceyan.com/tech/mongodb_repset2.html
注意點(diǎn)
- 服務(wù)器節(jié)點(diǎn)之前時間要同步
- 開啟防火墻的一定要允許通過
- 開啟selinux的也要進(jìn)行設(shè)置
- 建立雙擊互信模式最好不過
格式化阿里云的新增硬盤
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進(jìn)程
rm -rf /data/replset/
ps -ef|grep mongod | awk '{print $2}' | xargs kill -9
ps -ef|grep mongod
創(chuàng)建目錄
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
準(zhǔn)備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,所以啟動需要點(diǎn)時間
初始化
> 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' }]})
這個其實也很慢。。。。
待完成后,繼續(xù)增加其他2個節(jié)點(diǎn)(一定要注意,在rs:PRIMARY即主節(jié)點(diǎn)上才能增加rs:SECONDARY和ARBITER。如果之前連的是其他端口,需要切換的。)
rs.add("10.51.77.129:27001")
rs.addArb("10.51.77.129:27002")
查看狀態(tài)
rs.status();
如果想移除某一個節(jié)點(diǎn)
rs.remove("10.51.77.129:27001")
rs.remove("10.51.77.129:27000")
rs.remove("10.51.77.129:27002")
reconfig
如果想刪除,重置用rs.reconfig(),這樣做不一定會成功,有的時候無法切換到主節(jié)點(diǎn),所以需要,刪除/data/replset目錄,然后重啟所有mongo的進(jìn)程。
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節(jié)點(diǎn)無法show dbs
主從啟動之后,連接slave可以成功連上,但是在slave中執(zhí)行 show dbs 的時候就報錯了:
QUERY Error: listDatabases failed:{ "note" : "from execCommand", "ok" : 0, "errmsg" : "not master" }
解決方法:
在報錯的slave機(jī)器上執(zhí)行 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
內(nèi)存問題
查看內(nèi)存情況最常用的是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
限制內(nèi)存
所有連接消耗的內(nèi)存加起來會相當(dāng)驚人,推薦把Stack設(shè)置小一點(diǎn),比如說1024:
ulimit -s 1024
通過調(diào)整內(nèi)核參數(shù)drop_caches也可以釋放緩存:
sysctl vm.drop_caches=1
有時候,出于某些原因,你可能想釋放掉MongoDB占用的內(nèi)存,不過前面說了,內(nèi)存管理工作是由虛擬內(nèi)存管理器控制的,幸好可以使用MongoDB內(nèi)置的closeAllDatabases命令達(dá)到目的:
mongo> use admin
mongo> db.runCommand({closeAllDatabases:1})
平時可以通過mongo命令行來監(jiān)控MongoDB的內(nèi)存使用情況,如下所示:
mongo> db.serverStatus().mem:
{
"resident" : 22346,
"virtual" : 1938524,
"mapped" : 962283
}
還可以通過mongostat命令來監(jiān)控MongoDB的內(nèi)存使用情況,如下所示:
shell> mongostat
mapped vsize res faults
940g 1893g 21.9g 0
其中內(nèi)存相關(guān)字段的含義是:
- mapped:映射到內(nèi)存的數(shù)據(jù)大小
- visze:占用的虛擬內(nèi)存大小
- res:占用的物理內(nèi)存大小
注:如果操作不能在內(nèi)存中完成,結(jié)果faults列的數(shù)值不會是0,視大小可能有性能問題。 在上面的結(jié)果中,vsize是mapped的兩倍,而mapped等于數(shù)據(jù)文件的大小,所以說vsize是數(shù)據(jù)文件的兩倍,之所以會這樣,是因為本例中,MongoDB開啟了journal,需要在內(nèi)存里多映射一次數(shù)據(jù)文件,如果關(guān)閉journal,則vsize和mapped大致相當(dāng)。
see
更好的做法是使用docker,一勞永逸
- 手把手教你用Docker部署一個MongoDB集群 http://dockone.io/article/181
全文完
http://my.oschina.net/nodeonly/blog/471834
歡迎關(guān)注我的公眾號【node全棧】
posted on 2015-06-30 10:30 paulwong 閱讀(1895) 評論(0) 編輯 收藏 所屬分類: MONGODB