從?
mongodb 階段性技術總結
?中抽取并整理了對大家有幫助的十個要點:
?
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 左右。
?
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。
虛擬機可以很好的隔離資源,并可動態的擴展。
我們建議 mongodb 的部署采用虛擬機的方式,每個虛擬機部署一個實例,使各節點分散在不同的物理機上,根據應用的前期預測,平衡虛擬機的之間的i/o。
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
