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 (複製羣集,副本集): html

背景: 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 部署方案。
圖例:
http://images.cnblogs.com/cnblogs_com/zhengyun_ustc/255879/o_clipboard%20-011%20%E5%89%AF%E6%9C%AC.png
另,使用 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)。
http://images.cnblogs.com/cnblogs_com/zhengyun_ustc/255879/o_clipboard%20-%20012%E5%89%AF%E6%9C%AC.png
Config Server 對整個集羣的健康運行是相當重要的,因此一旦你選擇使用 分片機制,就必定要保證生產環境裏有3個 Config Servers 。
永遠不要刪除 Config Servers 的數據,要確保頻繁地對這些數據進行平常備份。若是可能,經過域名來指定節 點的地址,好比在/etc/hosts文件中指定相應的本地域名,這能讓你在集羣配置上更靈活。Config Servers 的壓力很小,但仍是必須運行在 64-bit instances 上。
千萬不要把3個 Config Servers 都放在同一個 instance 上!
 
 
參考資源:
3)部份內容來自宋濤,劉奎波和孫國璽
4)nosqlfan, mongodb資料彙總專題
贈圖幾枚:
70e7cafagw1dzu7kaec4fg.gif (440×570)
61d40ffatw1dlsxs3ux51j.jpg (320×240)
67efa0c0gw1dzu4ghfrl9j.jpg (440×316)
相關文章
相關標籤/搜索