1. 程式人生 > >記一次 MongoDB 佔用 CPU 過高問題的排查

記一次 MongoDB 佔用 CPU 過高問題的排查

1. 引言

今天檢視監控無意間突然發現自己的伺服器上,CPU 佔用率飆升到 100%,load 升到 10 以上,登入的響應已經達到半分鐘。
馬上執行 top,發現主要是 mongodb 佔用了大量的 CPU,這是為什麼呢?又該如何解決呢?

#此處有圖片

2. 分析正在執行的請求

通過執行命令:

db.currentOp()

我們可以看到資料庫當前正在執行的操作:

#此處有圖片

2.1. 官方文件

https://docs.mongodb.com/manual/reference/method/db.currentOp/?spm=a2c4e.11153940.blogcont73389.10.2c402b90x4iad1。

2.2. 包含資訊

主要有以下資訊:

  • client – 請求是由哪個客戶端發起的
  • opid – 操作的opid,有需要的話,可以通過 db.killOp(opid) 殺死操作
  • secs_running/microsecs_running – 請求執行的時間,如果這個值特別大就非常值得注意
  • query/ns: 對集合進行的具體操作
  • lock*:鎖相關引數

3. 開啟慢請求日誌

MongoDB 支援 profiling 功能,將請求的執行情況記錄到同DB下的 system.profile 集合裡,profiling 有3種模式:

  1.  0 – 關閉 profiling
  2.  1 – 針對慢請求 profiling,將超過一定閾值的請求,記錄到system.profile 集合
  3.  2 – 針對所有請求開啟 profiling,將所有請求的執行都記錄到 system.profile 集合

3.1. 通過命令開啟

推薦在生產環境中設定為 1,開啟慢請求日誌,方便問題的暴露和排查,可以通過下面命令設定 profiling 級別:

db.setProfilingLevel(1, { slowms: 20 })

{ slowms: 20 } 引數就是慢請求執行閾值,單位是毫秒。

3.2. 通過配置檔案開啟

也可以通過配置檔案開啟:

operationProfiling:
  mode: slowOp
  slowOpThresholdMs: 100

3.3. 檢視慢請求記錄

下面的命令中我們獲取了最近的3條慢請求記錄:

db.system.profile.find().sort({$natrual: -1}).limit(3)

4. 慢請求分析 – 全表掃描 COLLSCAN

如果在日誌中看到關鍵字 COLLSCAN,說明該查詢在進行全表掃描,通常這就是 CPU 異常飆高的主要原因。

4.1. 檢視掃描文件數

system.profile 裡 docsExamined 的值顯示了本次查詢的掃描文件數。

4.2. 解決辦法 – 新增索引

最好針對查詢語句建立索引:

db.col.createIndex({"title":1})

我們也可以在新增索引時增加傳入可選引數,例如,在生產環境我們通常不希望索引新增的操作阻塞其他資料庫操作,這時就需要務必新增 background 引數:

db.col.createIndex({"title":1}, {'background', true})

5. 慢請求分析 – 索引設定不合理

有的時候,請求即使查詢走了索引,執行也很慢,通常是因為索引建立不太合理或者匹配結果太多。
索引通常應該建立在區分度大的欄位上。
在 system.profile 中,可以通過 keysExamined 欄位檢視查詢掃描了多少條索引,如果該值過大,要考慮建立新的索引或優化查詢了。

6. 慢請求分析 – 大量資料排序

當查詢請求裡包含排序的時候,如果排序無法通過索引滿足,MongoDB 會在記憶體中對結果進行排序。
大家都知道,排序是非常消耗 CPU 的一項操作,最好在需要排序的欄位上建立索引。

system.profile 中的 SORT 關鍵字反映了查詢需要排序。

7. 服務能力評估

有時 CPU 消耗過高僅僅是單純的因為伺服器達到了上限。
如果上面的措施都無法讓 CPU 佔用率下降到合理的指標內,就要考慮擴容、升級來提升服務能力的上限。
但切忌將這個方法作為首要考慮的解決方案,合理的設定索引,建立資源預警,而不是盲目提升配置或在業務已經達到上限時再考慮優化。

8. 參考資料

https://docs.mongodb.com/manual/reference/method/db.currentOp/?spm=a2c4e.11153940.blogcont73389.10.2c402b90x4iad1。
https://docs.mongodb.com/manual/tutorial/manage-the-database-profiler/?spm=a2c4e.11153940.blogcont73389.11.2c402b90x4iad1。
https://docs.mongodb.com/manual/reference/database-profiler/?spm=a2c4e.11153940.blogcont73389.13.2c402b90WPcbsr。
https://yq.aliyun.com/articles/73389。
http://www.runoob.com/mongodb/mongodb-indexing.html。