Mongodb CPU占用率達90%的優化調整報告


1問題描述

1.1現場的數據庫部署情況

    服務器基本情況如下:

CPU

20邏輯核,40線程

內存

64 G

硬盤

D盤 :1T SSD

E盤:3T SATA

F盤:3T SATA

 

在這台機器上同時部署有postgresql和mongodb數據庫。其中postgresql數據庫存儲入庫后的矢量數據,mongodb存儲矢量瓦片數據。

生成矢量切片的大致流程為:

  1. 查詢mongodb數據庫,檢查哪些切片還未生成;
  2. 查詢postgresql數據庫,根據切片范圍進行空間查詢;
  3. 對第2)步查詢結果進行切片處理,並將切片寫入mongodb

1.2異常情況說明

    剛開始作業時,效率尚可。然而當作業持續進行一段時間后,效率變得很低,甚至完全hang住不動了。同事分析,認為可能是postgresql空間查詢效率過低導致。

2問題診斷

    由於機器上部署有兩個不同的數據庫,並且,切片全流程會涉及到兩個數據庫。因此需要首先定位,到底慢在哪個數據庫上?又或者,甚至還可能是操作系統級別的某種問題?

    先通過性能監視器查看系統性能。一看就發現了問題,在切片程序hang住不動的時候,mongodb服務進程占用CPU的比率達到了90%以上,以至於服務器CPU負載長時間處於92%-99%。

    首先定位到了是mongodb拖慢了速度,那么接下來,需要分析到底是mongodb中的什么操作拖慢了速度。

    通過設置profile=1,slowms=100 ,並開啟httpinterface option,然后在http://localhost:28017上監控mongodb中的log,發現了這樣的一些日志信息:

    -----------------------------------------------------------------------------------------------------------

……(省略若干行)

Command vindex.矢量瓦片測試_道路_線 command {count : "矢量瓦片測試_道路_線"} ,query :{fx:808 ,fy:189 ,flevel:10} } planSummary COLLSCAN keysExamined 0 docsExamined:2627694 numYields:20529 reslen:44 locks :{acquireCount :{r:41060}} ,MMAPV1Journal :{acquireCount :{r:20569}},Database :{acquireCount :{r:20530}},Collection:{acquireCount :{R:20530},acquireWaitCount : {R:39},timeAcquiringMicros:{R:}

……(省略若干行)

2017-01-17T17:32:11.816+0800 I COMMAND [conn187] vindex.矢量瓦片測試_道路_線 query: {$query: { flevel:3}, $orderby : {$natural:1}} planSummary : COLLSCAN ntoreturn : 500000 ntoskip:500000 keysExamined :0 docsExamined:3288241 cursorExhausted :1 numYields:25694 nreturned:0 reslen:20 locks:{ Global: {acquireCount :{r:51390}} ,MMAPV1Journal:{acquireCount: {r:25695}},Database:{ acquireCount:{r:25695}},Collection:{acquireCount:{R:25695}}} 8121ms

……(省略若干行)

-----------------------------------------------------------------------------------------------------------

先看第一條日志記錄。一個簡單的count查詢,執行計划顯示進行了COLLSCAN,即掃描集合。該次掃描掃描了2627694個文檔,然而返回的數據集只有44KB,另外,執行這樣一次查詢,獲得鎖的次數為41060,其中為了獲得鎖等待了39次。

再看第二條日志記錄。這是一個query操作,查詢結果進行了基於$natural(即基於數據在磁盤中的存儲順序)的排序。執行計划顯示進行了COLLSCAN,即掃描集合。該查詢使用了limit(500000).skip(500000)條件,為了獲得500000個文檔記錄,共掃描了3288241個文檔,可是nreturned返回結果為0,說明查詢了這么多,卻沒有符合條件的文檔。另外,執行這樣一次查詢,獲得鎖的次數為51390。

分析到這里,問題已經很明顯了。之所以發生這么多無效的掃描,原因在於集合中沒有創建合適的索引,導致每次查詢都要對集合進行掃描,而該集合目前已經達到了550GB的體量。

 

3調整方式

  1. 創建索引。

通過vindex.矢量瓦片測試_道路_線.ensureIndex({flevel:1,fx:1,fy:1}{unique:true})

方法創建基於flevel,fx,fy三列的唯一值索引;

  1. 修改query查詢語句

第二條SQL中使用於基於$natural的排序,一般情況下使用$natural排序,是要告訴mongodb,本次查詢不要使用索引。這樣就意味着將從磁盤的順序返回數據,強制mongodb不使用索引。它適用如這樣一種場景:如果你創建了索引,但是要求返回大量的數據,通過索引來查詢是很低效的,這時候你可以通過再sort中指定{"$natural":1}來強制不使用索引。而在本例中,flevel=3(還有flevel=4,flevel=5等)是從大量數據中返回極少量的數據,因此,使用$natural排序是不合適的。可將sort方式改為基於_id排序。

4調整后效果

    在使用上述調整方式調整之后,服務器CPU使用率穩定在10%左右,切片進程不再出現hang住的情況。廣東省整省數據,用1個小時就全部切片完畢。

5其它說明

    盡管當前效率尚可,但通過mongostat進程監控mongodb服務器進程的性能發現,qw(隊列中等待寫的客戶端進程數)達到30-50,說明在往mongodb中寫的過程仍然存在很大的優化空間。改善寫的性能,可以通過分片的技術手段解決。不過目前未在現場實施改造。其原因有二:

  1. 目前的切片效率滿足要求,不需要另行改造
  2. 目前沒有其它的服務器來部署分片架構
  3. 雖然當前服務器有3塊可用磁盤(1.1現場的數據庫部署情況),但通過HDTunePro的測試,發現兩塊SATA盤的iops僅為60-70左右,不適合用做數據庫文件存儲。因此,預計,即便在多塊磁盤上實現了分片,也不會改善性能,甚至會降低性能。


免責聲明!

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



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