簡體   English   中英

如何在Node.js / V8中調試/分析極長的GC暫停

[英]How to debug/analyze extremely long GC pauses in Node.js/V8

我試圖在一個相對復雜的Node.js服務器應用程序中分析內存/ GC問題。 即使在非常適中的負載下,它也會在明顯的時期內變得無法響應,並且隨着時間的推移這些停頓會變得更長。 使用--trace-gc參數運行可能會導致極長的垃圾回收時間:

[4805]      537 ms: Mark-sweep 17.6 (46.4) -> 10.3 (47.4) MB, 20 ms [allocation failure] [GC in old space requested].
[4805]     1338 ms: Mark-sweep 31.3 (58.4) -> 19.2 (57.2) MB, 40 ms [allocation failure] [promotion limit reached].
[4805]     2662 ms: Mark-sweep 58.0 (79.2) -> 43.9 (85.2) MB, 109 ms [Runtime::PerformGC] [promotion limit reached].
[4805]     4014 ms: Mark-sweep 90.1 (111.5) -> 70.6 (113.9) MB, 114 ms [allocation failure] [promotion limit reached].
[4805]     7283 ms: Mark-sweep 129.7 (153.9) -> 112.0 (158.9) MB, 511 ms [allocation failure] [promotion limit reached].
[4805]    10979 ms: Mark-sweep 184.6 (210.9) -> 160.3 (212.9) MB, 422 ms [Runtime::PerformGC] [promotion limit reached].
[4805]  1146869 ms: Mark-sweep 243.8 (271.4) -> 191.6 (267.9) MB, 1856 ms [allocation failure] [promotion limit reached].
[4805]  1731440 ms: Mark-sweep 282.1 (307.4) -> 197.5 (298.9) MB, 1 / 11230 ms [allocation failure] [promotion limit reached].
[4805]  2024385 ms: Mark-sweep 291.0 (320.8) -> 197.3 (306.9) MB, 9076 ms [Runtime::PerformGC] [promotion limit reached].
[4805]  2623396 ms: Mark-sweep 290.9 (317.1) -> 196.9 (311.9) MB, 1 / 15401 ms [allocation failure] [promotion limit reached].
[4805]  3223769 ms: Mark-sweep 291.4 (323.6) -> 187.8 (318.9) MB, 1 / 13385 ms [allocation failure] [promotion limit reached].
[4805]  4225777 ms: Mark-sweep 280.1 (324.2) -> 190.6 (315.9) MB, 1 / 13266 ms [allocation failure] [promotion limit reached].
[4805]  4705442 ms: Mark-sweep 286.2 (321.4) -> 195.2 (314.9) MB, 1 / 17256 ms [Runtime::PerformGC] [promotion limit reached].
[4805]  5225595 ms: Mark-sweep 288.3 (324.0) -> 201.7 (316.9) MB, 1 / 22266 ms [Runtime::PerformGC] [promotion limit reached].
[4805]  6127372 ms: Mark-sweep 296.5 (324.6) -> 200.5 (316.9) MB, 1 / 28325 ms [allocation failure] [promotion limit reached].
[4805]  6523938 ms: Mark-sweep 297.8 (328.9) -> 198.8 (323.9) MB, 1 / 27213 ms [allocation failure] [promotion limit reached].
[4805]  7355394 ms: Mark-sweep 292.1 (330.7) -> 223.9 (322.9) MB, 60202 ms [allocation failure] [promotion limit reached].

可以在此處找到完整的( --trace-gc-verbose )輸出。

這些日志是使用以下參數運行服務器的結果:

--expose-gc --trace-gc --trace-gc-verbose --trace-gc-ignore-scavenger --max-old-space-size=1000

它運行的時間越長,停頓時間越長(通常為幾分鍾),直到最后幾小時后完全鎖定。 可用內存永遠不會用完,RSS甚至沒有接近1000mb舊空間限制,因此它似乎不是泄漏。 在我看來,代碼中可能存在一些相當不尋常的東西,這使得GC在可接受的時間范圍內完成工作非常“困難”。

我的問題是:我如何進一步分析這個問題,並縮小可能的原因? 任何可以推薦的工具來幫助解決這樣的問題? 我本質上是在尋找一種更有效的方法,而不是天真地關閉和部分代碼,這是非常麻煩和耗時的。

順便說一句,我非常感謝任何文檔的鏈接,這些文檔解釋了GC調試輸出中使用的術語/消息(例如“達到促銷限制”)以及那里列出的數字。 我對V8 GC的工作方式有了非常基本的了解( 有很大幫助),但大部分輸出仍然超出了我的范圍。

如果重要:這是在Ubuntu 14.04服務器上的Node.js v0.10.33上運行的。

編輯:前一段時間我們轉移到io.js,這個問題根本不再發生(可能是由於更新的V8版本)。 我從來沒有找到Node v0.10這個問題的原因,更不用說修復了。

您是否能夠在單個節點上重現該問題? 我想如果我遇到這種情況,我可能會混合使用以下內容:

  • 編寫一個允許我在本地實例上復制的加載器
  • 如果沒有,請在prod中放置一個將接收流量子集的實例,並修改它以執行以下操作
  • node-heapdump添加到源,以一定間隔調用它,並以N分鍾為間隔將結果導出到json文件。
  • 可能,如果你在本地運行,你也可以利用memwatch
  • 等待慢速GC啟動。
  • 當您知道GC開始緩慢時,請抓住一些堆轉儲。
  • 將它們加載到chrome中並使用三種快照技術進行分析(我想你可以在我們的例子中稱之為N快照技術)

基本上,您將加載堆並開始查看它們以嘗試了解堆疊的東西是什么類型,持有它的結果是什么,因此您將了解GC為什么花費這么長時間。

可用內存永遠不會用完,RSS甚至沒有接近1000mb舊空間限制,因此它似乎不是泄漏。 在我看來,代碼中可能存在一些相當不尋常的東西,這使得GC在可接受的時間范圍內完成工作非常“困難”。

在這里,您可能正在尋找長而圓形的保留樹。 但是在一天結束的時候,即使是這樣,你也應該能夠確定樹的根是什么,它的內容是什么,並嘗試減少刪除的方法。

我也同意@dandavis和可疑的關閉。

這個答案可能沒有具體的,你想,但我建議你看包好了這就是沃爾瑪的一部分hapi.js框架。 它在將記錄擴展到--trace-gc之外做得很好。 它是一個偵聽以下一個或多個事件的進程監視器:

  • ops - 系統和進程性能 - CPU,內存,磁盤和其他指標。
  • response - 有關傳入請求和響應的信息。 這映射到hapi服務器發出的“響應”或“尾部”事件。
  • log - 記錄信息未綁定到特定請求,例如系統錯誤,后台處理,配置錯誤等。映射到hapi服務器發出的“log”事件。
  • error - 請求狀態代碼為500的響應。這將映射到“請求錯誤”hapi事件。
  • request - 請求記錄信息。 這映射到通過request.log()發出的hapi'request'事件。

您必須拉入Hapi庫才能實現此功能,但出於調試目的,它可能暫時值得。 總的來說,我強烈推薦Hapi用於擴展Node.js應用程序,沃爾瑪的這些人在過去的一年中一直在做着驚人的事情。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM