MongoDB CPU使用較高,如何排查?


前言

首先,我們簡單梳理一下,CPU 在什么情況下才算負載較高?負載查看是通過"uptime"命令查看。大家都知道,命令顯示的結果分別表示1分鍾、5分鍾、15分鍾的負載情況,這點就不多做說明。在系統負荷方面,多核CPU與多CPU效果類似,所以考慮系統負荷的時候,必須考慮這台電腦有幾個CPU、每個CPU有幾個核心。然后,把系統負荷除以總的核心數,只要每個核心的負荷不超過1.0,就表明電腦正常運行。從單棵CPU來說,一般負載不超過0.7都無需關系,當超過該值得時候,就應該開始調查了,問題出在哪里,防止情況惡化。

負載計算公式:

[root@mongodb-1219 ~]# grep 'model name' /proc/cpuinfo | wc -l
24
[root@mongodb-1219 ~]# echo "0.7 * 24" |bc
16.8

N個CPU的電腦,可接受的系統負荷最大為n。正常情況為"N * 0.7",該值為可觀狀態。

案例

[root@mongodb-1219 ~]# top
top - 09:58:34 up 325 days, 14:15,  5 users,  load average: 84.13, 156.16, 108.10
Tasks: 1078 total,   1 running, 1077 sleeping,   0 stopped,   0 zombie
%Cpu(s):  2.9 us,  0.2 sy,  0.0 ni, 96.8 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem : 32639968 total,  1817952 free,   998372 used, 29823644 buff/cache
KiB Swap: 16777212 total, 16773128 free,     4084 used. 29489896 avail Mem 

   PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND                                                  
333052 root      20   0 34.607g 657716 262228 S  74.3  2.0 209:12.13 mongod                                                   
366752 root      20   0  147216   3128   1432 S   1.0  0.0   0:02.50 top                                                      
367511 root      20   0  147072   3024   1416 R   1.0  0.0   0:00.19 top                                                      
  2189 root      20   0  686788  36396   4188 S   0.3  0.1 267:57.64 salt-minion                                              
     1 root      20   0   69856  31864   1964 S   0.0  0.1  15:13.08 systemd

如圖所示,該服務器CPU使用高達74%(截圖存在一定的偏差,其實此時的用戶占用CPU值相當高)。根據信息可以得知,是用戶態CPU使用較高,那么這種情況一般都是用戶使用不合理。這種情況,不僅在MongoDB中,MySQL中也會有類似的問題。

Setup 1.查看相關日志

查看日志,發現有條查詢語句竟然耗時7077ms,看樣子有問題。(此時估摸着,就是開發沒有加索引。)

Setup 2.分析數據庫正在執行的請求

用戶可以通過 Mongo Shell 連接,並執行 db.currentOp() 命令,能看到數據庫當前正在執行的操作,如下是該命令的一個輸出示例,標識一個正在執行的操作。重點關注幾個字段:

  client:請求是由哪個客戶端發起的;

  opid:操作的opid,有需要的話,可以通過 db.killOp(opid) 直接干掉的操作;
  secs_running/microsecs_running: 這個值重點關注,代表請求運行的時間,如果這個值特別大,就得注意了,看看請求是否合理;
  query/ns: 這個能看出是對哪個集合正在執行什么操作;
  lock*:還有一些跟鎖相關的參數,需要了解可以看官網文檔,本文不做詳細介紹;

Setup 3.分析數據庫的慢請求

MongoDB 支持 profiling 功能,將請求的執行情況記錄到同DB下的 system.profile 集合里,profiling 有3種模式:
  關閉 profiling
  針對所有請求開啟 profiling,將所有請求的執行都記錄到 system.profile 集合
  針對慢請求 profiling,將超過一定閾值的請求,記錄到system.profile 集合
  默認請求下,MongoDB 的 profiling 功能是關閉,生產環境建議開啟,慢請求閾值可根據需要定制,如不確定,直接使用默認值100ms。

 關於profiling功能說明,參考文檔。默認請求下,MongoDB 的 profiling 功能是關閉,生產環境建議開啟,慢請求閾值可根據需要定制,如不確定,直接使用默認值100ms。

operationProfiling:
  mode: slowOp
  slowOpThresholdMs: 100

基於上述配置,MongoDB 會將超過 100ms 的請求記錄到對應DB 的 system.profile 集合里,system.profile 默認是一個最多占用 1MB 空間的 capped collection。

查看最近3條 慢請求,{$natrual: -1} 代表按插入數序逆序
db.system.profile.find().sort({$natrual: -1}).limit(3)

情況1:全盤掃描

       全集合(表)掃描 COLLSCAN,當一個查詢(或更新、刪除)請求需要全表掃描時,是非常耗CPU資源的,所以當你在 system.profile 集合 或者日志文件發現 COLLSCAN 關鍵字時,就得注意了,很可能就是這些查詢吃掉了你的 CPU 資源;確認一下,如果這種請求比較頻繁,最好是針對查詢的字段建立索引來優化。

        一個查詢掃描了多少文檔,可查看 system.profile 里的 docsExamined 的值,該值越大,請求CPU開銷越大。關鍵字:COLLSCAN、 docsExamined。

情況2:索引未添加或不合理

       一個走索引的查詢,掃描了多少條索引,可查看 system.profile 里的 keysExamined 字段,該值越大,CPU 開銷越大。關鍵字:IXSCAN、keysExamined。

情況3:大量數據排序

       當查詢請求里包含排序的時候,如果排序無法通過索引滿足,MongoDB 會在內存里將結果進行排序,而排序這個動作本身是非常耗 CPU 資源的,優化的方法仍然是建立索引,對經常需要排序的字段,建立索引。當你在 system.profile 集合 或者 日志文件發現 SORT 關鍵字時,就可以考慮通過索引來優化排序。當請求包含排序階段時, system.profile 里的 hasSortStage 字段會為 true。關鍵字:SORT、hasSortStage。

       其他還有諸如建索引,aggregationv等操作也可能非常耗 CPU 資源,但本質上也是上述幾種場景;建索引需要全表掃描,而vaggeregation 也是遍歷、查詢、更新、排序等動作的組合。

      基本上就是以上幾種情況,還有的話就是MongoDB確實已經達到瓶頸,此時可能需要通過shard來解決。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM