Mongodb效能調優 -效能優化建議
摘要
1.
MongoDB 適用場景簡介
2. Mongodb 效能監控與分析
3. Mongodb 效能優化建議
關於Mongodb的幾個大事件
1.根據美國資料庫知識大全官網釋出的DB熱度排行,Mongodb的熱度排名從2014年的第5名,在2015年躍升為第4名,僅次於主流DB(Oracle、MySQL、SQLServer)之後。
2.2015第六屆中國資料庫技術大會(DTCC)上,Mongodb高調宣佈收購開源引擎WiredTiger,效能在3.0版本上實現了7~10倍的提升。
Mongodb 適用場景簡介
適用場景
1. 實時的CRU操作,如網站、論壇等實時資料儲存
2. 高伸縮性,可以分散式叢集,動態增刪節點
3. 儲存大尺寸、低價值資料
4. 快取
5. BSON結構物件儲存
不適用場景
1. 高度事務性操作,如銀行或會計系統
2. 傳統商業智慧應用,如提供高度優化的查詢方式
3. 需要SQL的問題
4. 重要資料,關係型資料
Mongodb 效能監控與分析
mongostat
1. faults/s:每秒訪問失敗數,即資料被交換出實體記憶體,放到SWAP。
若過高(一般超過100),則意味著記憶體不足。
vmstat & iostat & iotop
si:每秒從磁碟讀入虛擬記憶體的大小,若大於0,表示實體記憶體不足。
so:每秒虛擬記憶體寫入磁碟的大小,若大於0,同上。
mongostat
2. idx miss %:BTree 樹未命中的比例,即索引不命中所佔百分比。
若過高,則意味著索引建立或使用不合理。
db.serverStatus()
indexCounters” : {
“btree” : {
“accesses” : 2821726, #索引被訪問數
“hits” : 2821725, #索引命中數
“misses” : 1, #索引偏差數
“resets” : 0, #復位數
“missRatio” : 3.543930204420982e-7 #未命中率
}
mongostat
3. locked %:全域性寫入鎖佔用了機器多少時間。當發生全域性寫入鎖時,所有查詢操作都將等待,直到寫入鎖解除。
若過高(一般超過50%),則意味著程式存在問題。
db.currentOp()
{
“inprog” : [ ],
“fsyncLock” : 1, #為1表示MongoDB的fsync程序(負責將寫入改變同步到磁碟)不允許其他程序執行寫資料操作
“info” : “use db.fsyncUnlock() to terminate the fsync write/snapshot lock”
}
mongostat
4. q r|w :等待處理的查詢請求佇列大小。
若過高,則意味著查詢會過慢。
db.serverStatus()
“currentQueue” : {
“total” : 1024, #當前需要執行的佇列
“readers” : 256, #讀佇列
“writers” : 768 #寫佇列
}
mongostat
5. conn :當前連線數。
高併發下,若連線數上不去,則意味著Linux系統核心需要調優。
db.serverStatus()
“connections” : {
“current” : 3, #當前連線數
“available” : 19997 #可用連線數
}
6.連線數使用記憶體過大
shell> cat /proc/$(pidof mongod)/limits | grep stack | awk -F 'size' '{print int($NF)/1024}'
- 1
- 1
將連線數使用Linux棧記憶體設小,預設為10MB(10240)
shell> ulimit -s 1024
優化器Profile
db.setProfilingLevel(2);
0 – 不開啟
1 – 記錄慢命令 (預設為>100ms)
2 – 記錄所有命令
info: #本命令的詳細資訊
reslen: #返回結果集的大小
nscanned: #本次查詢掃描的記錄數
nreturned: #本次查詢實際返回的結果集
millis: #該命令執行耗時(毫秒)
- 表KnowledgeAnswer未建立有效索引(建議考慮使用組合索引)
- 存在大量慢查詢,均為表KnowledgeAnswer讀操作,且響應超過1秒
- 每次讀操作均為全表掃描,意味著耗用CPU(25% * 8核)
- 每次返回的記錄位元組數近1KB,建議過濾不必要的欄位,提高傳輸效率
執行計劃Explain
db.test.find({age: “20”}).hint({age:1 }).explain();
cursor: 返回遊標型別(BasicCursor 或 BtreeCursor)
nscanned: 被掃描的文件數量
n: 返回的文件數量
millis: 耗時(毫秒)
indexBounds: 所使用的索引
- 在查詢條件、排序條件、統計條件的欄位上選擇建立索引
db.student.ensureIndex({name:1,age:1} , {backgroud:true});
注意:
最新或最近記錄查詢,結合業務需要正確使用索引方向:逆序或順序
建議索引建立操作置於後臺執行,降低影響
實際應用過程中多考慮使用複合索引
使用limit()限定返回結果集的大小,減少資料庫伺服器的資源消耗,以及網路傳輸的資料量
db.posts.find().sort({ts:-1}).limit(10); -
只查詢使用到的欄位,而不查詢所有欄位
db.posts.find({ts:1,title:1,author:1,abstract:1}).sort({ts:-1}).limit(10); -
基於Mongodb分散式叢集做資料分析時,MapReduce效能優於count、distinct、group等聚合函式
-
Capped Collections比普通Collections的讀寫效率高
db.createCollection(“mycoll”, {capped:true, size:100000});
例:system.profile 是一個Capped Collection。
注意:
固定大小;Capped Collections 必須事先建立,並設定大小。
Capped Collections可以insert和update操作;不能delete操作。只能用 drop()方法刪除整個Collection。
預設基於 Insert 的次序排序的。如果查詢時沒有排序,則總是按照insert的順序返回。
FIFO。如果超過了Collection的限定大小,則用 FIFO 演算法,新記錄將替代最先 insert的記錄。 -
Mongodb 3.0.X版本效能較Mongodb 2.0.X有7-10倍提升,引入WiredTiger新引擎,同時支援MMAPv1記憶體對映引擎
注意:
預設MMAPv1,切換至WiredTiger:mongod –dbpath /usr/local/mongodb/data –storageEngine wiredTiger
備註:若更換新引擎,則之前使用舊引擎建立的DB資料庫無法使用。 建議先通過Mongodb的同步機制,將舊引擎建立的DB資料同步到從庫, 且從庫使用新引擎.
選擇 Windows 2008 R2 x64 或 Linux x64,Linux版本效能優於 Windows,建議基於Linux系統進行架構選型
根據RHEL版本號選擇Mongodb相應Linux版本
Mongodb Driver 與 Mongodb 版本一致
最後的建議
哪一種物理設計更適合Mongodb:正規化化 & 反正規化化 & 業務 ?
正規化化設計的思想是“完全分離”,存在關聯查詢,查詢效率低,但寫入、修改、刪除效能更高
反正規化化設計的思想是“資料集中儲存”,查詢效率高,而Mongodb對查詢機制支援較弱,看似成為一種互補
下面我們來看一個圖書資訊DB表設計案例:
示例1:正規化化設計
{
"_id" : ObjectId("5124b5d86041c7dca81917"),
"title" : "MongoDB效能調優",
"author" : [
ObjectId("144b5d83041c7dca84416"),
ObjectId("144b5d83041c7dca84418"),
ObjectId("144b5d83041c7dca84420"),
]
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
分析:更新效率高,因為不需要關聯表操作。比如更新作者年齡,只需要更新作者資訊1張表就可以了。而查詢效率低,因為需要關聯表操作。比如檢視某本圖書的作者簡介,需要先查圖書資訊表以獲取作者ID,再根據ID,在作者資訊表中查詢作者簡介資訊。
示例2:反正規化化設計
{
"_id" : ObjectId("5124b5d86041c7dca81917"),
"title" : "MongoDB效能調優",
"author" : [
{
"name" : "張三"
"age" : 40,
"nationality" : "china",
},
{
"name" : "李四"
"age" : 49,
"nationality" : "china",
},
{
"name" : "王五"
"age" : 59,
"nationality" : "china",
},
]
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
分析:將作者簡介資訊嵌入到圖書資訊表中,這樣查詢效率高,不需要關聯表操作。依然是更新作者年齡,此時更新效率就顯得低,因為該作者出過多本書,需要修改多本圖書資訊記錄中該作者的年齡。
示例3:不完全正規化化設計
{
"_id" : ObjectId("5124b5d86041c7dca81917"),
"title" : "MongoDB效能調優",
"author" : [
{
"_id" : ObjectId("144b5d83041c7dca84416"),
"name" : "張三"
},
{
"_id" : ObjectId("144b5d83041c7dca84418"),
"name" : "李四"
},
{
"_id" : ObjectId("144b5d83041c7dca84420"),
"name" : "王五"
},
]
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
分析:其實我們知道某本書的作者姓名是不會變化的,屬於靜態資料,又比如作者的年齡、收入、關注度等,均屬於動態資料,所以結合業務特點,圖書資訊表肯定是查詢頻率高、修改頻率低,故可以將一些作者的靜態資料嵌入到圖書資訊表中,做一個折中處理,這樣效能更優。
總結:Mongodb效能調優不是最終或最有效的手段,最高效的方法是做出好的物理設計。而什麼樣的物理設計適合Mongodb,最後還是由當前業務及業務未來發展趨勢決定的。最後送給大家一句話“好的效能不是調出來的,更多是設計出來的”!