您好,登錄后才能下訂單哦!
這篇文章主要講解了“如何優化JVM OOM”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“如何優化JVM OOM”吧!
剛接手的服務,正常穩定運行了很長一段時間,在大家伙收拾東西準備回家過年時,突然就抽風了。
接口失敗率居高不下?
看日志!
GC overhead limit exceeded
java.lang.OutOfMemoryError:GC overhead limit exceeded
看一下JVM堆棧
sudo jmap -heap port
#eg:sudo jmap -heap 9999
很明顯,是內存不夠了。
我當時的第一想法就是,應該是內存泄漏!我的思路如下:
1、先入為主,因為之前處理過一次因內存泄漏導致的JVM OOM問題,所以當時高度懷疑內存泄漏。
2、導出JVM堆數據,分析、定位問題。
3、fix bug,重新部署,finish!
我按照這個思路,分析堆棧后,發現堆中有大量對象,這些對象還沒來得及回收,其他線程又在申請內存,從而導致了OOM。造成問題的直接原因是業務請求量增加了,而現有的機器資源不夠用。至于間接原因,下一篇文章再詳細描述。
在揭開問題的謎底后,回過頭想一想,如果當時能夠仔細分析一下問題,或許問題會被更快解決。
事后反思:服務已經穩定正常運行了一段時間,且一個月內未修改代碼和更新服務。如果是代碼有問題,那么問題極大可能會在新代碼上線后的幾天內出現。基于這一點,基本可以排除代碼問題。
線上服務出現問題,首要的任務就是盡快恢復服務可用。如果下次出現類似問題,我會選擇流程一,而非流程二。
造成服務不可用的直接原因是服務請求量上升,而根本原因是由于下游服務負載過高,導致微服務調用超時,從而引起連鎖反應。
下圖呈現了用戶發起請求到響應完成的大致流程。
業務服務接口和算法服務接口使用eureka作為服務注冊中心,整體來說,這個服務采用相對簡單的微服務架構。
服務接口搭配feign來請求算法服務接口。
@FeignClient(value = "image-service")
public interface ImageService {
@PostMapping(value = "/XXX")
String XXX(@RequestParam("img_base64") String imgBase64);
}
上面的代碼在執行請求的時候,會將請求參數進行拼接。
image-service/xxx?img_base64=fjsfdgldfgrwdfdmgfdglwefsl
當eureka真正確定請求的服務地址后,又會再做一次拼接處理。
127.0.0.1:5000/xxx?img_base64=fjsfdgldfgrwdfdmgfdglwefsl
算法服務接口的處理時間與圖片的大小正相關,圖片越大,處理時間越長。由于處理圖片是一個相對耗時的操作,接口會出現超時的情況。如果請求失敗(超時),那么feign會進行重試。
圖片base64字符串的長度與圖片大小呈正相關關系,圖片越大,base64字符串長度越長。一張306K的圖片,轉成base64格式后,字符串長度為429196。
因此處理一次正常的請求消耗的內存比較大。圖片越大,算法處理時間越久,超時失敗后,feign重試,重試之后又失敗,導致一個惡性循環(幸好有超時次數限制,否則如此遞歸下去,后果不堪設想)。
如圖是JVM OOM后拿到堆棧的數據,最大的圖片base64的大小有5M。
jdk1.8 JVM參數PretenureSizeThreshold的默認值是2M。
當base64字符串超過2M時,會直接分配到老年代,這無疑加大了JVM老年代的內存壓力,導致頻繁Full GC。
為何使用image base64傳輸圖片?
1、歷史原因。
2、開發相對簡單。
該如何優化?
1、提高feign請求的超時時間。
2、提高機器配置。
3、將image base64放到請求體中,減少因feign框架對參數進行拼接帶來的內存開銷。
感謝各位的閱讀,以上就是“如何優化JVM OOM”的內容了,經過本文的學習后,相信大家對如何優化JVM OOM這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。