從零開始搞監控系統(4)——內存泄漏


  在將監控日志的服務獨立部署后,還是發現CPU會在不特定時間段(例如21~22、23~02等)飆到70%,內存也是一路飆升不會下降,明顯是出現了內存泄漏。

  

  

  需要進一步做優化,於是開通了阿里雲的 Node.js 性能平台

一、Node.js性能平台

  要使用此工具需要在自己的服務器中安裝些組件的,具體步驟參考官網說明,公司運維操作起來蠻快的,下圖是平台中的數據趨勢。

  

  點擊堆快照,就會生成一個*.heapsnapshot文件,通過該文件就能查看內存的分布和使用情況,點擊下圖中的轉儲就能查看分析了。

  

   但是我怎么點,每次都是失敗,后面找了阿里雲的技術人員,他說是因為文件太大,下載的時候總是會斷開,無奈,只能在服務器上手動下載,然后在本地Chrome中加載了。

二、分析

  在該平台上下載了堆快照(*.heapsnapshot文件),在Chrome的Memory選項卡中載入,可以看到下圖內容。

  

1)任務隊列(Kue.js)

  翻看其中的幾列,發現內存中滯留了很多隊列任務的數據,於是鎖定內存暴漲與隊列有關。

  然后開始查代碼,並且在本地做了調試,發現在任務完成后沒有將其標記為成功,因為聲明的那個改變狀態的函數沒有被執行。

  只有標記成功的任務才會被自動清除,由於狀態沒有更新,導致滯留在內存中,從而使得內存一直在漲而不會降。

  一頓操作猛如虎,但是最后發布上去后,內存並沒有降下來,依然在增長中,說明不是這個問題。

  在創建隊列任務時會打條日志,然后在完成任務后,會再打一條日志,發現一分鍾內會創建大約4、5百個任務,但是完成的任務只有200個,甚至更少。

  也就是出隊的速度沒有入隊快,隊列來不及處理任務。如此下去的話,就會將任務堆積在一起。

  馬上為隊列處理的方法加了個並發的參數,再用LoadTest模擬並發,效果非常理想,任務有條不紊地被處理了,於是發布了代碼。

  若要結束並發測試,mac電腦可執行命令 kill -USR2 36155,其中 36155 是端口號。

  

  但高興的還是太早,雖然為隊列加了並發的設置,但滯留的任務並沒有減少,猜想可能是任務中的邏輯阻塞了任務的完成,繼續將耗時邏輯注釋掉,內存並沒有如預期那樣降下來。

  再次分析,感覺是上面配置的並發沒有生效,很奇怪,查看Kue.js源碼也沒看出個所以然來。

  只能另辟蹊徑了,也就是多創建幾種類型,但處理的邏輯是一樣的,以此來彌補任務隊列的吞吐量。

for (let i = 1; i <= 3; i++) {
  const taskName = "handleMonitor" + i;
  queue.process(taskName, (job, done) => {
    services.common
      .handleMonitor(job.data.monitor)
      .then(() => {
        done();
      })
      .catch((err) => {
        done(err);
      });
  });
}

  查看日志,發現隊列的入和出已經平衡,但是內存仍然會升,沒有降的趨勢。

2)繼續分析

  再次觀察堆快照,我一度懷疑是 SequelizeKOA 或 Node.js 8.0版本的問題,翻來覆去的查,雖然的確看到了內存泄漏的蛛絲馬跡,但仍然沒有起色。

  后面將兩份堆快照做對比,在查看增長的數據時,發現我請求的 ma.gif 路徑中的變量不會釋放,存在着一個閉包,八成是這個原因導致內存一直漲。

  

  於是仔細查看代碼,將最可疑的一句代碼注釋掉,如下所示,省略了其他邏輯,就放出了關鍵的那句代碼,為外部的 queue 對象反復注冊了一個error事件。

import queue from "../util/queue";
router.get("/ma.gif", async (ctx) => {
  queue.on('error', function( err ) {
    logger.trace('handleMonitor queue error', err);
  });
});

  沒想到內存一下子平穩了,沒有出現暴增的情況。一波多折后發現,原來是自己寫的代碼不對導致內存的泄漏。

  

 

參考資料:

Node.js 內存管理和 V8 垃圾回收機制

Loadtest庫做負載測試

Memory Usage Bug

4類 JavaScript 內存泄漏及如何避免

Node.js 調試指南

有意思的 Node.js 內存泄漏問題

 


免責聲明!

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



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