一、背景
上週五,其他項目組違背了週五不能發版的規定,18:30
下班前兩個系統發了新版
19:30
運營反饋系統很卡,華爲雲CPU
100%報警
二、解決思路
因爲應用服務器不同項目組是共用的,影響到我負責的系統,所以我也幫忙排查
第一直覺判斷應該是內存泄露或大對象
因爲數組內存分配在Oracle
JDK8
空間必須是連續的(IBM
J9
不是),如果大對象無法申請到足夠的內存,那麼就會OOM
檢查週五提交的代碼記錄,發現select *
和where
條件名字數據在20W
,並且使用Stream.collect
產生新集合,局部變量一直持有原集合,預估數據量在40W
左右,並且接口屬於數據同步類型的,基本上每2分鐘一次拉取,因爲大數據查詢耗時,算上併發時客戶端數量在20個左右,峯值數量在800W
,這僅僅是其中一個數據同步接口,如果應用服務器其他接口內存申請觸發GC
,處理延遲,峯值更高,由於都存在引用,full gc
也無法回收內存,故JVM
拋出OOM
先回滾了代碼,定位問題大概用了20-30分鐘
三、思考
拋開代碼code review
和開發的問題,談談大對象的優化
通常大對象發生的場景
- 數據導入導出
- 文件服務器
- 批處理任務 ......
優化的方法
- 可以每次取小量,使用offset記錄偏移量,在循環中處理
- 在使用完後的數據,後續不用時,對局部變量賦值爲null,這種在處理耗時較長場景提升較大
- 儘量不要查出數據在應用中聚合統計
- 流處理(mybatis支持流和遊標返回數據)
原理就是尋找大數據小內存的通用解