sql未做限制導致的應用fullGc排查過程

因爲怕踩高壓線的緣故很多內容不敢發,這篇文章記錄的事件實際是在2020年10月發生的.

這是工作以來見到的第N+起sql未做限制導致的內存溢出,依稀還記得上一次看到這類問題時寫的文章: https://my.oschina.net/110NotFound/blog/3129213

晚上19點40,同事報了測試環境某服務掛了,當時第一想法是重啓,但是重啓之後又出現了類似的問題,應用啓動後所有的接口不通。

看了下應用日誌,沒有明顯的報錯日誌刷新,但是ssh到機器上明顯感到卡頓,top命令一看,cpu佔用非常高。

top -H -p pid 看了下進程對應的線程:

將線程id轉換爲16進制之後在jstack查了下,對應的全是gc線程佔用cpu80%以上。

"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x00007f0ca401e000 nid=0x539 runnable 

"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x00007f0ca4020000 nid=0x53a runnable 

"GC task thread#2 (ParallelGC)" os_prio=0 tid=0x00007f0ca4021800 nid=0x53b runnable 

"GC task thread#3 (ParallelGC)" os_prio=0 tid=0x00007f0ca4023800 nid=0x53c runnable 

看了下gc日誌,3秒一次fullgc,一次gc平均2秒,說明此時去看jstack已經意義不大,應該關注下堆棧情況,什麼對象多導致了頻繁的gc。

先簡單的執行了下jmap看個大概:

jmap -histo:live 1335 結果如下:

八九不離十就是這個對象的問題了:

xxx.xxx.xxx.xxx.db.ProductAdRecognitionHistory

因爲是測試環境,所以用jmap命令沒有影響,其次應用此時已經無法提供服務了(生產環境慎重,會stw整個應用)。

導出整個堆棧:

jmap -dump:format=b,file=xxxxxheapdump.hprof pid

下載好eclipse的mat圖形化工具: MemoryAnalyzer

https://www.eclipse.org/mat/

因爲堆棧文件有點大,需要設置下mat工具的最大分配堆內存, 修改 MemoryAnalyzer.ini 文件的最大堆內存爲 -Xmx8000m

打開 xxxxxheapdump.hprof ,加載完成後查看內存泄漏報告, 發現裏面是這樣的:

xxx.xxx.xxx.xxx.db.impl.ProductAdRecognitionHistoryDaoImpl$$EnhancerBySpringCGLIB$$44b54bd5.findByTraceId(Ljava/lang/String;)Ljava/util/List; (Unknown Source)
at xxx.xxx.xxx.xxx.ProductAdRecognitionHistoryServiceImpl.updateAidByTraceId(Ljava/lang/String;Ljava/lang/Long;)V (ProductAdRecognitionHistoryServiceImpl.java:xx)
at xxx.xxx.xxx.xxx.ProductIdentifyServiceImpl.updateRecognitionHistoryxxx(Ljava/lang/String;Ljava/lang/Long;)Z (ProductIdentifyServiceImpl.java:xx)
at xxx.xxx.xxx.xxx.ProductController.advertiseReturnxxx(Ljava/util/List;)xxx/xxx/xx/xx/xx/ServiceResponse; (ProductController.java:xx)

疑似內存泄漏的地方都指向了

ProductAdRecognitionHistoryServiceImpl.updateAidByTraceId

且裏面的 ProductAdRecognitionHistory 對象一次執行就有 80w個。

看了下代碼,updateAidByTraceId方法是這樣的:

問題就浮現了,當 traceId爲空的時候,會把所有的爲空的數據全部查詢出來,數據量80w+,和我們的堆棧分析是吻合的。

總結

查詢語句需要做改進,邏輯上要對這個查詢字段進行判斷校驗,同時查詢的sql也要限制查詢結果的長度,這樣可以防止查詢出的數據過大,打爆內存。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章