天天看點

55最佳實踐系列:MongoDB最佳實踐

@鄭昀彙總 建立日期: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 部署方案。 圖例:

55最佳實踐系列: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)。

55最佳實踐系列:MongoDB最佳實踐

Config Server 對整個叢集的健康運作是至關重要的,是以一旦你選擇使用 分片機制,就一定要保證生産環境裡有3個 Config Servers 。 永遠不要删除 Config Servers 的資料,要確定頻繁地對這些資料進行日常備份。如果可能,通過域名來指定節 點的位址,比如在/etc/hosts檔案中指定相應的本地域名,這能讓你在叢集配置上更靈活。Config Servers 的壓力很小,但還是必須運作在 64-bit instances 上。 千萬不要把3個 Config Servers 都放在同一個 instance 上!    本文首發于 旁觀者-鄭昀的 55最佳實踐系列,連結: http://www.cnblogs.com/zhengyun_ustc/archive/2012/12/15/mongodb_bp.html   參考資源: 1)程式員雜志: Engine Yard眼中的MongoDB最佳實踐 英文原文:  http://www.engineyard.com/blog/2011/mongodb-best-practices  2)Kristina Chodorow, 50 Tips and Tricks for MongoDB Developers 3)部分内容來自宋濤,劉奎波和孫國玺 4)nosqlfan, mongodb資料彙總專題 贈圖幾枚:

55最佳實踐系列:MongoDB最佳實踐
55最佳實踐系列:MongoDB最佳實踐
55最佳實踐系列:MongoDB最佳實踐