@鄭昀匯總 創建日期:2012/9
Application Design:
1)
如果發現query沒使用你預期的索引,請用hint強制使用指定索引
主站商品中心所使用的文檔字段很多,各種索引建得也不少。在沙創排查慢查詢時,曾百思不得其解,為什么明明建的有聯合索引,查詢起來還是非常慢呢,直到顯式指定使用該聯合索引。
hint的例子:
db.collection.find({"age" : 18, "username" : /.*/}).hint({"username" : 1, "age" : 1})
2)
Design documents to be self-sufficient,
設計
自給自足的文檔
MongoDB 應該是一個大的、無聲的數據存儲(big, dumb data store)。它幾乎不需做任何處理,只是負責存儲和讀取數據。你應該堅持這個目的,避免強迫 MongoDB 做一些客戶端可以進行的計算工作。
如果真的想算一些文檔里沒有顯式存儲的數據,你有兩個選擇:
——招致嚴重的性能懲罰(讓 MongoDB 用JavaScript 做運算);
——在文檔中顯式存儲這些數據。
Implementation:
3)
Override _id when you have your own simple, unique id
如果你的文檔自己有明確的唯一鍵值,不需要 ObjectId 屬性,那么請覆蓋默認的 _id 字段,反正你也要在自己的 unique id 上建唯一索引。
Optimization:
4)數據量很大時,建聯合索引時,不妨對比下索引升序和降序的查詢效率
db.collection.ensureIndex({"store_id":- 1, "shop_id": 1})
上面的1代表ascending升序,-1代表descending降序。
單個字段建索引時,不需要考慮索引升序還是降序,都行。
但聯合索引下的排序或范圍查詢(包括$in, $gt, $lt 等),需要重視索引設為升序還是降序。孫國璽認為,最好用大數據模擬一下業務場景,商戶中心曾發現設-1比1快10倍以上。
5)如需在聯合索引下排序,索引的建立方法
MongoDB 和 MySQL 都是B-Tree結構索引,所以一般來說,聯合索引都可以這么建:
查詢語句是:
db.collection.find({x : 1,y : 2}).sort({z : 1})
那么,索引可以是:
db.collection.ensureIndex({x : 1, y : 1,z : 1})//即x+y+z
也可以是:
db.collection.ensureIndex({y : 1, x : 1,z : 1})//即y+x+z
排序字段總在聯合索引的最后。
盡量把能過濾數據量多的字段放在前面。
但如果涉及范圍查詢(Range Queries),就要小心了。
查詢語句是:
db.collection.find({"country": {"$in": ["ZH", "EN"]}}).sort({"cars": 1})
那么較好的索引是:
db.collection.ensureIndex({"cars": 1,"country": 1})
即,在范圍查詢(包括$in, $gt, $lt 等)時,其實刻意在后面追加排序索引通常是沒有效果的。因為在進行范圍查詢的過程中,我們得到的結果集本身並不是按追加的這個字段來排的,還需要進行一次額外的排序才行。而在這種情況下,可能反序建立索引(排序字段在前、范圍查詢字段在后)反而會是一個比較優的選擇。當然,是否更優也和具體的數據集有關,還是要實測。
再舉一個例子:
查詢語句是:
db.collection.find({x : 1,y : {$in:[1,2]}}).sort({z : 1})
那么較好的索引是:
db.collection.ensureIndex({x : 1, z : 1,y : 1})//即x+z+y
6)養成用 explain 確認是否充分利用了索引的
習慣
請確認你的查詢是否充分利用到了索引,用explain命令查看一下查詢執行的情況,添加必要的索引,避免掃表操作。
7)查詢盡量采用分頁,並且盡快釋放游標
8)
避免使用不會命中索引的語法,如 $nin
Data Safety and Consistency:
9)總是使用 Replica Sets (復制群集,副本集):
背景:
Replica Sets
通過自動 failover 機制提供MongoDB的高可用性。Replica sets are a form of asynchronous
master/slave replication, adding automatic failover and automatic recovery of member nodes
應用點:在應用中,如 primary 機器出現故障,那么某一台 secondary 機器就會通 過選舉成為新的 primary ,整個集群仍然能夠提供正常服務。我們的服務不會支持無同步機制的 MongoDB 部署方案。
圖例:

另,使用 Replica Sets 時,最好加1台仲裁服務器。
10)
默認開啟 journaling 日志:
背景:64-bitMongoDB 1.9.2+以上默認開啟
Journaling 功能。32-bit或1.9.2以下版本,則需在命令行啟動時加上 --journal 。
Journaling 的出現歸因於某用戶在單機使用 MongoDB 時執行了 kill -9 操作,導致數據不可用后提出的。
開啟該功能時,變更會先寫入 Journaling 日志,定期集中提交,然后在真實數據上進行這些變更。如果服務器安全關閉,日志會被清除。在服務器啟動時,如果存在 Journaling 日志,則會進行回放。這保證了那些已寫入、但在服務器崩潰前還沒有回放的日志能在用戶連接前被執行。
應用點:
鄭昀強烈建議你在部署時開啟 Journaling 日志。注意數據文件的存放位置。在使用時,請確認你的數據文件處於一個持久化存儲中(比如/data /mongodb目錄)。也可以使用非持久化的設備進行數據文件存儲,不過你最好小心再小心,因為這可能會對你的集群架構造成影響。
熱數據最好能放在內存中。能夠保持熱數據(以及索引數據)一直放在內存中,這一點非常重要,它將對整個集群的性能造成影響。如果通過監控發現 page fault 的數量增加,那么很可能就是熱數據量超出了可用內存大小。當熱數據量超出了可用內存量時,通常有兩種解決方法:增加內存和數據分片。建議先增加內存,再考慮通過數據分片的方式解決。
Administration:
11)
保持版本更新:
應用點:保持版本更新很重要,10gen 在每個版本中都會修復一些問題,使 MongoDB 的運行更出色。比如在 2.0.x版本中,MongoDB 的存儲性能和並發性能就有極大提高,同時還包括索引優化、Bug修復以及 compaction 命令等一系列改進。
12)
不要在32位系統上使用MongoDB:
背景:在32位機器上,MongoDB只能存儲約2.5GB的數據。因為 MongoDB在內部實現上是通過內存映射的方式來提高性能的,所以在32位機器上其內存地址本身就限制了數據容量。
13)
壓力過大升級服務器配置:
應用點:如果機器負載達到65%,那么應該考慮升級機器配置。在日常使用中,最好保持負載低於65%。同時這也對數據恢復和縱向擴展有影響。
14)
確定熱數據大小:
使用MongoDB,你最好保證你的熱數據在你機器的內存大小之下,保證內存能容納所有熱數據。
15)
選擇正確的文件系統:
MongoDB 的數據文件是采用的預分配模式,並且在 Replication 里面,Master 和 Replica Sets 的非 Arbiter 節點都是會預先創建足夠的空文件用以存儲操作日志。
這些文件分配操作在一些文件系統上可能會非常慢,導致進程被 Block 。所以我們應該選擇那些空間分配快速的文件系統。這里的結論是盡量不要用ext3,用ext4或者xfs。
16)
選用合適的raid和磁盤:
盡量使用raid10,避免使用raid5,經濟條件允許的情況下最好使用ssd硬盤。
17)如何
關閉 MongoDB:
MongoDB 數據庫在關閉的時候使用 kill -2 <mongo-pid>,
或者在 mongo 終端中使用
use admin
db.shutdownServer()
18)
分片(
sharding)
需謹慎:
應用點:分片策略會受數據訪問特點的影響,所以在進行數據分片前,最好先理清楚數據的訪問模式,並想明白是否確實需要分片。
由於 Shard Key 對性能的影響非常大,所以
選擇一個好的 Sharding Key 是非常重要的。對於 Shard Key 的選定直接決定了集群中數據分布是否均衡、集群性能是否合理。選擇 Shard Key 的一個非常重要因素是萬一某一個分片徹底不可訪問了,受到影響的Chunk有多大(即使是用 Replica Set)。
Config Server 對整個集群的健康運行是至關重要的,所以一旦你選擇使用 分片機制,就一定要保證生產環境里有3個 Config Servers 。
永遠不要刪除 Config Servers 的數據,要確保頻繁地對這些數據進行日常備份。如果可能,通過域名來指定節 點的地址,比如在/etc/hosts文件中指定相應的本地域名,這能讓你在集群配置上更靈活。Config Servers 的壓力很小,但還是必須運行在 64-bit instances 上。
千萬不要把3個 Config Servers 都放在同一個 instance 上!
參考資源:
1)程序員雜志:
Engine Yard眼中的MongoDB最佳實踐
2)Kristina Chodorow,
50 Tips and Tricks for MongoDB Developers
3)部分內容來自宋濤,劉奎波和孫國璽
4)nosqlfan,
mongodb資料匯總專題
贈圖幾枚: