记一次内存泄漏问题的排查经历
源寶導讀:隨著系統越來越龐大,越來越復雜,疑難雜癥問題也越來越多。本文將介紹明源研發協同平臺團隊針對一次內存泄露問題的排查過程和技術探索。
一、背景
? ? 內存泄漏,一個說大不大說下不小的瑕疵。作為開發者,我們都很清楚內存泄漏是我們代碼問題導致的。但是話說回來,泄漏后果會很嚴重嘛?這不好說,如果對服務器內存的影響只有幾個百分點,又或者對應用沒有什么致命影響,那么修補內存泄漏就像雞肋一樣,“食之無味,棄之可惜”。反之內存泄漏也可能導致服務不可用,嚴重影響用戶體驗。
二、問題
? ? 19年年初,協同平臺后臺服務開始間歇性非正常重啟,每次重啟耗時2-5分鐘,重啟期間服務不可用;并且事發前用戶觸發的部分任務沒有重試機制,一些中間狀態的數據需要人工修復。
? ? 初步排查是程序池內存溢出引起的IIS自動回收,監控看板顯示服務器內存從50%瞬間漲到100%,十幾分鐘之后觸發回收,內存才徹底降下來。
? ? 此后重啟事件陸續不斷,間隔從數小時到數天不等,每次重啟前毫無征兆,沒有規律可循,下圖是服務的內存走勢圖。
三、事件分析
? ? 通常內存泄漏最常規的做法是抓取Dump包,然后分析Dump包中的堆棧數據。但這次內存泄漏并非緩慢上升,而是瞬間將內存吃滿,沒有多余的硬件資源供抓包工具使用。更重要的是這個后臺服務職責過重,也非常重要,屬于一個在線系統,隨便都有用戶訪問,抓包工具在進行抓包過程中會中斷進程,影響服務使用。所以抓取Dump包的方案被暫時擱置。
? ? 在翻遍所有日志沒有找到蛛絲馬跡之后,決定采用分治策略排除法,先將事故影響的范圍慢慢縮小。
四、垂直拆分
? ? 前文提到后臺服務職責過重,需要進行拆分,這個是年初團隊達成的共識,方案是先將后臺作業任務獨立出來,此次事件是個契機。新增一個調度服務,將現有定時作業和主動長時作業兩塊邏輯包含進去。拆分之后,主服務恢復正常,重啟問題轉移至新增的調度服務,風險隨之降級,雖然問題沒有解決,但是兩個服務的事故級別是不一樣的,主服務恢復正常后,至少不會對用戶產生直接影響。
? ? 雖然是一次投鼠忌器的嘗試,好在結果符合預期,滿足分治的需求,現在已經可以確定,元兇肯定就在調度服務的代碼中。
五、監控埋點
? ??現在范圍縮小了許多,定時作業和主動長時作業兩大類,其中的子任務加起來不超過20個,將所有任務的開始和結束各記一次埋點。隨后觀察重啟發作時間點與兩大類后臺作業的開始時間進行匹配,所有的任務都可以正常的開始,并正常的結束,沒有一類任務的執行時間與重啟時間點完全匹配,后臺任務的嫌疑全部排出。
六、動態抓包
? ? 排查陷入了僵局,再次觀察監控看板,分析現有數據:調度服務的進程內存,正常值在400m-700m之間波動,出現異常時內存在2分鐘內,由正常值上升至最高值,最高值接近系統總內存,這個與最初的癥狀有所不同,起初內存是90度直線瞬間吃滿,現在是在2分鐘內45度吃滿內存。有了2分鐘的緩沖期,可能與內存擴容有關,也可能與垂直拆分有關,原因不得而知,但這一點變化使得Dump抓包成為可能。
? ? 這里推薦使用ProcDump,ProcDump是一個輕量級的Sysinternal團隊開發的命令行工具,它的主要目的是監控應用程序的CPU內存異常動向,并在此異常時生成crash dump文件,供研發人員和管理員確定問題發生的原因。你還可以把它作為生成dump的工具使用在其他的腳本中。
? ? 根據調度服務內存正常值的區間范圍,內存閾值設置為1.5G,超過1.5g認為內存異常。按照ProcDump官網的介紹,ProcDump可以在閾值條件(內存、CPU、異常)到達時,自動觸發Dump抓取,但是我部署在服務器ProcDump在一定時間后會出現假死現象,不能后臺作業,也不知道下一次重啟什么時候來臨。無奈臨時編寫一個小工具,需求很簡單,實時監控進程內存,10s輪詢一次,超過閾值執行“procdump.exe -ma dotnet.exe“命令抓取Dump,下面是關鍵代碼:
七、內存分析
? ? 在小工具完成的第二天便成功捕捉到了傳說的“黑匣子”,如空難事故中一樣,它記錄了程序在宕機前的性能指標。
? ? 堆中數據顯示,兩個字符串數組占據了大部分內存空間,進一步跟蹤到是一個zip包解壓函數,在讀取文件流時,while循環的退出條件判斷有誤,引起了死循環,無論系統內存有多大,都可以在短時間將服務器內存吃滿。代碼并非每次都會進來,具有一定的隨機性,取決于用戶的操作,所以重啟沒有規律。
? ? 這段業務屬于長時作業任務,在上面第五步的監控埋點中,記錄了定時作業和主動長時作業兩大類的執行結果,唯獨這個被動長時作業任務成了漏網之魚,沒有納入監控體系。
八、總結
? ? 雖然修復這個Bug的工作量很小,但Bug持續時間長,影響較大。事后團隊做了兩點改進措施,一是研發流程中加入代碼掃描工具,將這類“低級錯誤”攔截在開發階段,避免提交到測試環境和生產環境;二是繼續完善了現有監控數據,將被動長時作業任務的執行情況,展示在監控看板上,如果某個任務執行失敗,或者只有開始沒有結束,監控看板會及時發送提醒,為排查類似問題提供線索,快速定位類似問題。
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的记一次内存泄漏问题的排查经历的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Flink or Spark?实时计算框
- 下一篇: 原子变量、锁、内存屏障,写得非常好!