MongoDB的十個使用要點

chenfeng發表於2016-06-30
1.mongodb 表名和欄位名統一用小寫字母

mongodb 是預設區分大小寫的,為了避免以前在 mysql 下遇到的大小寫敏感導致程式訪問頻頻出錯,
建立規範,mongodb 的表名和欄位名都用小寫字母命名。


2.儘可能的縮短欄位名的長度

mongodb 的 schema free 導致了每筆資料都要儲存它的 key 以及屬性,這導致了這些資料的大量冗餘。


開發人員也許考慮到,從易讀性出發設計的 key 名,基本都是按照字面意思去設計的,這導致 key 很長,對應的資料儲存佔用了很大的空間。


所以,在你的程式裡維護一套字典即可,儘可能降低 key 的長度。


譬如:




static final String CONTENT = "content";


static final String CONTENT_TYPE = "ctype";


static final String CONTENT_LENGTH = "clen";


 


3.記住,mongodb 的查詢每次只能用到一個索引


對於較複雜的表結構,可能會導致你頻頻使用聯合索引。


但記住:


1)mongodb 單表最大索引數為 64 。


2)索引越多,插入或修改記錄就會導致 mongodb 越慢。寫鎖會阻塞讀請求,寫得越慢,阻塞讀請求越多、阻塞時間越長。


所以,索引越加越多的時候,你可能需要審視一下表結構設計的合理性。


 




4.客戶端連線數大小的設定


mongodb-java-driver 的連線池,目前從觀察到的情況是應用一開啟便根據 connectionsPerHost 變數的設定,建立全部連線,然後提供給程式使用,並且一旦其中某個連線到資料庫的訪問失敗,
則會清空整個連線池到這臺資料庫的連線,並重新建立連線。


而 mongodb 對中斷連線的垃圾清理工作則是懶惰的被動清理方式,如果驅動程式端配置的連線數過大,一旦發生重連,則會導致 mongo 伺服器端堆積大量的垃圾連線以及對應資料,導致主機資源耗盡。


建議: mongodb 驅動的連線池大小的設定一般應該控制 100 左右。


( 參考閱讀:PHP-FPM模式下可怕的 MongoDB-PHP-Driver 連線池無節制連線問題)


 


5.例項分離




mongodb 對資料庫的訪問全部加鎖。


如是查詢請求則設定共享鎖。


資料修改請求則設定全域性排他鎖,且是例項級別的排他鎖。


寫鎖會阻塞讀請求,如果長時間持有寫鎖,會阻塞整個例項的讀請求。


建議:


1)不同應用不應該共用同一個例項,防止互相阻塞!


2)如伺服器資源不足,共用同一個例項,要保證讀寫特性相同,如都是讀多寫少,防止一臺寫多應用阻塞讀請求。


(評語:舊版本的MongoDB (pre 2.0)擁有一個全域性的寫入鎖,這個問題在2.0版本中的得到了顯著的改善,並且在當前2.2版本中得到了進一步的加強。MongoDB 2.2使用資料庫級別的鎖在這個問題上邁進了
一大步。所以用 MongoDB 2.2的人可以忽略此條目。)


 


6.需要重點關注的 mongodb 效能指標




關注主要效能指標:


1)Faults:顯示 mongodb 每秒頁面故障的數量,這個是 mongodb 對映到虛擬地址空間,而不是實體記憶體。這個值如果飆高的話,可能意味著機器沒有足夠的記憶體來儲存資料和索引。


2)Flushes:每秒做了多少次 fsync,顯示多少次資料被重新整理進了磁碟。


3)locked:寫鎖。


4)idx miss:索引未命中比例。


5)qr | qw:讀寫鎖的請求佇列長度。


6)conn: 當前已經建立的連線數。


 




7.嚴重的空間碎片問題


mongodb 如果資料修改很頻繁,會出現比較嚴重的空間碎片問題,表現在磁碟檔案擴張與實際資料量不相符,記憶體不夠用,索引命中率低,查詢效率降低。


碎片整理,目前我們採用的版本沒有太有效的方法。


可以用 db.repaireDatabase() 來整理資料庫,這個過程非常的慢。


如果是 master/slave 模式,則相當於執行一次主從切換,然後從新建立從庫。


如果是 replSet 架構,可以停掉資料庫,然後刪除資料目錄,從新從複製組中全同步資料,這個時候要考慮 oplog 的尺寸。


一個大體的步驟:


1)先呼叫rs.freeze(1200),將每個不想讓它成為 primary 的機器讓它在 1200 秒內無法成為 primary(這步也可以不做);


2)將 primary stepDown,不出意外新的 primary 會起來;


3)將原 primary kill 掉;


4)刪掉所有 data 資料(呼叫 repair 很慢,真不如干掉重新來);


5)再重啟動原 primary 的程式;


6)以此迴圈完成整個複製組的全部重建。


 


8.連線池 WriterConcern 模式選擇




有些應用配置了 WriterConcern.FSYNC_SAFE 模式;這種配置意味著客戶端在插入資料或更新資料的時候,要求 mongodb 必須將所更新的資料寫入磁碟並返回更新成功的資訊給程式。


如果碰上應用程式訪問壓力大,mongodb 就會反應遲鈍,並可能會假死。


針對此情況,需要評估資料的一致性需求,做出合適調整。


我們一般建議關閉此選項。


(評語:劉奎波的業務中心最佳化時就關閉了這個 WriterConcern.FSYNC_SAFE 模式)


 


9.開發時注意的細節


1)更新某條資料的時候,先查出來再更新會減小鎖的時間;


2)只有真正需要的欄位才select出來;


3)只有返回很少結果的查詢才用索引,否則會載入太多資料,比沒有用索引還慢!


4)屬性比較多的時候,建立分層的關係能夠提高查詢效率,否則每個記錄都要過一遍才能找到要的屬性。(評語:貌似說的是以 Array 形式儲存的 subdocument)


5)skip+limit 翻頁,越往後面越慢。比較靠譜的做法是,先找出上次的id,翻頁的時候不用 skip:


last_row_id = ObjectId('....');
db.activity_stream->find({_id:{$lt: last_row_id },user_id:20 } ).sort( {_id:-1} ).limit(10);


 


10.關於硬體資源的選擇
虛擬機器可以很好的隔離資源,並可動態的擴充套件。
我們建議 mongodb 的部署採用虛擬機器的方式,每個虛擬機器部署一個例項,使各節點分散在不同的物理機上,根據應用的前期預測,平衡虛擬機器的之間的i/o。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/15498/viewspace-2121237/,如需轉載,請註明出處,否則將追究法律責任。

相關文章