不知不覺房產(chǎn)系統(tǒng)已經(jīng)使用MongoDB一年多了,記得一年多以前,正是NOSQL被熱炒時(shí),MongoDB更是作為NOSQL中的佼佼者,被炒得火燙,也應(yīng)該就在當(dāng)時(shí)被這股火燙著了,所以義無反顧的選擇了MongoDB,現(xiàn)在想想當(dāng)時(shí)確實(shí)有些沖動了,當(dāng)時(shí)MongoDB的資料還是比較少,更別說中文資料了,后來還出現(xiàn)使用MongoDB成功應(yīng)用的范例Foursquare的宕機(jī)事件。現(xiàn)在確實(shí)應(yīng)該很感謝MongoDB為我們的系統(tǒng)服務(wù)了一年了,在這一年的時(shí)間里,確實(shí)出現(xiàn)過不少的小問題,特別是在管理操作上,我想這大概也是因?yàn)镸ongoDB在系統(tǒng)維護(hù)上不如Mysql那樣有著各種的業(yè)界實(shí)踐,往往就只能通過管理員自己去摸索。
下面將在這一年的一些簡單的管理操作做一下記錄
Starting and Stopping Mongo
MongoDB啟動
對了,MongoDB在linux下是無需安裝的,從官網(wǎng)上下載下安裝包后解壓,直接執(zhí)行mongod,就可以啟動MongoDB服務(wù)器,當(dāng)然mongod還有很多的啟動選擇項(xiàng),運(yùn)行mongod --help就可以查看所有的選擇項(xiàng)。
-f [ --config ] arg configuration file specifying additional options
一般來說,啟動選擇項(xiàng)可以直接寫在在mongod后面,也可以指定配置文件,用文件來加載各種啟動項(xiàng),如
/home/mongodb/bin/mongod --config /home/mongodb/conf/mongod.conf

上面是一臺測試機(jī)的啟動選擇項(xiàng)。
dbpath = /home/mongodb/data
指定數(shù)據(jù)庫的存儲目錄,如果不設(shè)置則以mongodb的根目錄為目錄,當(dāng)MongoDB啟動之后,在數(shù)據(jù)庫的存儲目錄下會創(chuàng)建一個(gè)mongod.lock文件,它是用來記錄當(dāng)前的mongod的進(jìn)程號,同時(shí)也用于區(qū)分各個(gè)mongod的進(jìn)程實(shí)例,所以不同的mongod進(jìn)程實(shí)例是不能用相同的dbpath。
logpath = /home/mongodb/mongodb.log
指定日志輸出的路徑,如果沒有設(shè)置logappend = true,系統(tǒng)會清除原來的日志記錄,把已有的文件進(jìn)行覆蓋。
logappend = true
日志以追加的方式進(jìn)行記錄
bind_ip = 192.168.86.111
指定對外服務(wù)的綁定ip,這里指定內(nèi)網(wǎng)的ip方式,如果外網(wǎng)無特殊的處理方式是無法進(jìn)行連接。
port = 27017
指定服務(wù)器的監(jiān)聽端口號,默認(rèn)是27017,如果單個(gè)機(jī)器要運(yùn)行多個(gè)mongod進(jìn)程,則需要給每個(gè)進(jìn)程指定不同的端口號。
fork = true
指定以守護(hù)進(jìn)程的方式來啟動MongoDB,如果不指定,在啟動mongod命令是加“&”也是可以的。
auth = true
啟動mongodb客戶端登錄的認(rèn)證機(jī)制。
master = true
指定該機(jī)器為主從模式下的主機(jī)器。
配置完配置文件后啟棟mongod,啟動時(shí)要盯著日志文件看,因?yàn)槿罩就ǔ嬖V我們一些錯誤或警告的信息,這樣能夠更好的幫助我們了解和避免錯誤。
這里給出了個(gè)提示,使用的是32位的Mongodb,所以MongoDB只是存儲最大為2GB的數(shù)據(jù)。其實(shí)這個(gè)跟MongoDB的mmap機(jī)制有關(guān),如果是64位則不會存在這種限制。
請注意一定要盯著日志看
tail -100f /home/mongodb/mongodb.log
停止MongoDB
千萬要強(qiáng)調(diào)的是千萬不要使用kill -9去關(guān)閉mongod!這樣數(shù)據(jù)庫會不理一切直接殺死該進(jìn)程,會使得數(shù)據(jù)文件損壞。
穩(wěn)妥的方法是使用kill -2 pid去關(guān)閉mongod,也就是當(dāng)mongod進(jìn)程接受到關(guān)閉指令后會等待當(dāng)前運(yùn)行操作或文件分配等操作完畢后,關(guān)閉所有打開的連接,并將緩存的數(shù)據(jù)刷新到磁盤后才正式關(guān)閉。
最穩(wěn)妥的方式是使用shutdown命令來結(jié)束
> use admin
switched to db admin
> db.shutdownServer();
Security and Authentication
打開mongodb.org的Security文檔,第一句話就是 Running Without Security(Trusted Environment),跟我們強(qiáng)調(diào)世界上沒有什么百分百安全的環(huán)境,最好的安全是放在一個(gè)安全的環(huán)境中運(yùn)行,這么無底氣的話語未免也讓人為它的安全擔(dān)心,不過事實(shí)上MongoDB還是有安全認(rèn)證模式的,只不過跟mysql對比起來有一點(diǎn)簡陋。
MongoDB的安全
MongoDB目前只支持最基本的安全認(rèn)證,如果我們開啟了安全性檢查,則只有數(shù)據(jù)庫認(rèn)證用戶才能進(jìn)行讀寫操作,當(dāng)然我們還可以創(chuàng)建讀寫權(quán)限用戶和只讀權(quán)限用戶,如果我們在admin的數(shù)據(jù)庫中進(jìn)行創(chuàng)建用戶,那么admin中的用戶就會被當(dāng)作超級用戶,超級用戶可以讀寫所有的數(shù)據(jù)庫,并且還可以進(jìn)行特殊的管理操作,比如可以再創(chuàng)建其他用戶關(guān)閉進(jìn)程等操作。
配置MongoDb用戶認(rèn)證
根據(jù)官網(wǎng)上的例子,我們也來創(chuàng)建一個(gè)超級用戶,一個(gè)test庫中具有讀寫操作的普通用戶,一個(gè)test庫中只有讀操作的普通用戶。
> use admin
switched to db admin
> db.addUser("cyz","abc")
{
"_id" : ObjectId("4dba5fe7c6792ae30fea3c31"),
"user" : "cyz",
"readOnly" : false,
"pwd" : "8658a5bf469e005b047560619ef0d51c"
}
> use test
switched to db test
> db.addUser("cyz001","abc")
{
"user" : "cyz001",
"readOnly" : false,
"pwd" : "7a597bef551027cc2161d5e0efe4049e"
}
> db.addUser("cyz002","abc",true)
{
"user" : "cyz002",
"readOnly" : true,
"pwd" : "2dde0a3777cd7dd92459a6c3f98afac6"
}
這里cyz是在admin庫中創(chuàng)建,屬于超級用戶,可以對所有庫進(jìn)行操作,在test庫中創(chuàng)建的cyz001和cyz002屬于test庫的操作人員,只能對test庫進(jìn)行相應(yīng)操作,記得要為安全驗(yàn)證生效需要將啟動項(xiàng)auth設(shè)置為true。
查看用戶
所有的用戶信息都存儲在每個(gè)數(shù)據(jù)庫的db.system.users中,可以使用find()進(jìn)行查看
> use admin
switched to db admin
> db.system.users.find()
{ "_id" : ObjectId("4dba5fe7c6792ae30fea3c31"), "user" : "cyz", "readOnly" : false, "pwd" :
"8658a5bf469e005b047560619ef0d51c" }
其中的pwd是根據(jù)用戶名和用戶密碼生成的散列值。
修改用戶
不管是添加用戶,修改用戶密碼,修改用戶操作權(quán)限都使用addUser()來完成。刪除用戶可以用remove()來實(shí)現(xiàn)。
> db.system.users.find({"user":"cyz001"})
更多的安全考慮
剛說了MongoDB的安全認(rèn)證其實(shí)還是簡陋的,所以我們還是有其他很多的安全考慮。
1.比如說MongoDB傳輸協(xié)議是不加密的,如果需要加密的話,我們可以考慮使用ssh隧道或是他們的技術(shù)來對客戶端和服務(wù)端之間的通訊進(jìn)行加密。
2.將MongoDB部署在只有客戶端服務(wù)器才能訪問到的環(huán)境,比如內(nèi)網(wǎng),vpn網(wǎng)絡(luò)中,可以使用 bind_ip = 本機(jī)或內(nèi)網(wǎng) 。
3.如果確實(shí)需要將MongoDB暴露在外部環(huán)境可以考慮使用IPTABLES等技術(shù)進(jìn)行訪問限制。
Monitoring and Diagnostics
官網(wǎng)首先給我們推薦了mongostat監(jiān)控工具,基本上mongostat可以作為一個(gè)外部觀測MongoDB內(nèi)部狀態(tài)指標(biāo)的工具,并且一秒更新一次,如果出現(xiàn)一些性能問題可以用這里入手進(jìn)行分析。

這里的屬性都可以通過mongostat --help進(jìn)行查看,有幾個(gè)列需要解釋一下,可以幫助到我們發(fā)生性能問題時(shí)比較準(zhǔn)備的找到定位。
faults:這是一個(gè)重要的性能指標(biāo),顯示你的機(jī)器每秒頁面故障的數(shù)量,這個(gè)是mongoDB映射到虛擬地址空間,而不是物理內(nèi)存,這個(gè)值如果飆高的話,可能意味著你的機(jī)器沒有足夠的內(nèi)存來存儲數(shù)據(jù)和磁盤的訪問。
flushes:每秒做了多少次fsync,表面多少次數(shù)據(jù)被刷新進(jìn)了磁盤。
mapped:是指mmap有多少數(shù)據(jù)量,也就是服務(wù)器的內(nèi)存映射,其中包含了虛擬內(nèi)存和常駐內(nèi)存。
locked:這個(gè)值表面全局寫入鎖占用了機(jī)器多少時(shí)間, 當(dāng)放生全局寫入鎖時(shí),所有的查詢操作都將等待,直到寫入鎖的解鎖,如果這個(gè)鎖飆高有可能是你的程序那部分出現(xiàn)問題。
idx miss:B樹未命中的比例,這個(gè)應(yīng)該是我們查詢的命中的實(shí)時(shí)指數(shù),一般在特定查詢中會有用到。
qr | qw:如果有太多的查詢進(jìn)行處理,它們就以一個(gè)隊(duì)列的方式進(jìn)行,如果這個(gè)值飆高的話,那么查詢也會變得很慢,因?yàn)楹竺娴年?duì)列必須等待前面的隊(duì)列執(zhí)行完畢,高并發(fā)時(shí),一般隊(duì)列值會升高。
另外我們還可以在mongodb shell中進(jìn)行檢查,使用db.serverStatus()

基本上db.serverStatus()跟mongostat 差不多,不過它顯示的數(shù)據(jù)更為具體,它也有一個(gè)缺陷就是它的數(shù)據(jù)是靜態(tài)的,不是實(shí)時(shí)的。
Http Console
其實(shí)mongodb還提供了一個(gè)跟直觀的檢測工具,在默認(rèn)情況下,啟動mongodb的同時(shí)還會啟動一個(gè)http的服務(wù)器,用網(wǎng)頁展示的信息比前兩個(gè)工具來得更加直觀,啟動默認(rèn)的監(jiān)聽端口為28017 http://ip:28017


基本上我們可以看到查詢,復(fù)制,鎖等等這些的情況,具體的參數(shù)還是上官網(wǎng)looklook,http://www.mongodb.org/display/DOCS/Http+Interface
當(dāng)然了,我們還可以使用其他的專業(yè)監(jiān)控軟件進(jìn)行監(jiān)控,如nagios,cacti,這些都有mongodb的插件。
Backups
MongoDB的備份機(jī)制還是不錯的,備份的方式也是很多,這個(gè)并不比mysql要差。
Shutdown and Backup
關(guān)閉服務(wù),直接把dbpath參數(shù)的目錄進(jìn)行備份,只需把所有的文件進(jìn)行復(fù)制到其他地方就可以,不過如果這個(gè)備份是在服務(wù)啟動時(shí)候做的話,有可能備份的文件會被損壞,雖然這種關(guān)閉服務(wù)的備份很有效也很安全,都效果相當(dāng)不理想。
mongodump & mongorestore
mongodump簡直就是mysqldump的另一版,如果你使用過mysqldump那就再熟悉不過了,mongodbdump可以使用在各個(gè)客戶端,對正在運(yùn)行的mongodb服務(wù)做出查詢,然后將所有查到的文本寫入到客戶端的磁盤。
除了mongodump,MongoDB還提供了從備份中恢復(fù)數(shù)據(jù)的工具mongorestore,mongorestore從mongodump獲取結(jié)果,并將備份的數(shù)據(jù)插入到運(yùn)行的MongoDB實(shí)例。
./mongodump --db test --collection user --out - > /home/chenyz/cyz.bson
./mongorestore --db test --collection user --directoryperdb /home/chenyz/cyz.bson --drop cyz.bson
上面的例子中,指定了要備份的db和要備份的collection,--drop表明要在恢復(fù)前刪除集合,否則,數(shù)據(jù)將和現(xiàn)有的集合數(shù)據(jù)合并。
主從備份
上面說的幾種備份數(shù)據(jù)方式已經(jīng)很靈活了,但都不及在從服務(wù)器上備份來得方便,從服務(wù)器的數(shù)據(jù)幾乎是于主服務(wù)器進(jìn)行同步,涉及到主從方面還有很多,從服務(wù)器備份就不放在這里講了。
修復(fù)
遇到一些停電,或非法關(guān)閉mongodb,不合理備份文件的操作,往往會出現(xiàn)文件損毀的提示,幸好,mongodb內(nèi)置的修復(fù)功能會試著去恢復(fù)損壞的文件。
操作很簡單,只需在啟動mongod 加入 --repair啟動項(xiàng),系統(tǒng)就會將所有的文件導(dǎo)入忽略那些無效的文檔然后進(jìn)行導(dǎo)入,完成之后,會重新建立索引,數(shù)據(jù)量大的話需要花費(fèi)很長的時(shí)間,因?yàn)樗械奈募夹枰M(jìn)行驗(yàn)證,所有的索引都需要重建,另外修復(fù)數(shù)據(jù)庫還能起到壓縮數(shù)據(jù)的作用,閑置的空間,碎片在修復(fù)后會被重新回收進(jìn)行使用。
另外在shell中也可以直接進(jìn)行repair操作
> db.repairDatabase()
{
"ok" : 1
}