一次容器化springboot程式OOM問題探險

来源:https://www.cnblogs.com/hyq0823/archive/2019/09/21/11564168.html
-Advertisement-
Play Games

背景 運維人員反饋一個容器化的java程式每跑一段時間就會出現OOM問題,重啟後,間隔大概兩天後復現。 問題調查 一查日誌 由於是容器化部署的程式,登上主機後使用docker logs ContainerId查看輸出日誌,並沒有發現任何異常輸出。 使用docker stats查看容器使用的資源情況, ...


背景

運維人員反饋一個容器化的java程式每跑一段時間就會出現OOM問題,重啟後,間隔大概兩天後復現。

問題調查

一查日誌

由於是容器化部署的程式,登上主機後使用docker logs ContainerId查看輸出日誌,並沒有發現任何異常輸出。 使用docker stats查看容器使用的資源情況,分配了2G大小,也沒有發現異常。

二缺失的工具

打算進入容器內部一探究竟,先使用docker ps 找到java程式的ContainerId
,再執行docker exec -it ContainerId /bin/bash進入容器。進入後,本想著使用jmap、jstack 等JVM分析命令來診斷,結果發現命令都不存在,顯示如下:

bash: jstack: command not found
bash: jmap: command not found
bash: jps: command not found
bash: jstat: command not found

突然意識到,可能打鏡像的時候使用的是精簡版的JDK,並沒有這些jVM分析工具,但是這仍然不能阻止我們分析問題的腳步,此時docker cp命令就派上用場了,它的作用是:在容器和宿主機之間拷貝文件。這裡使用的思路是:拷貝一個新的jdk到容器內部,目的是為了執行JVM分析命令,參照用法如下:

Usage:  docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH|-
        docker cp [OPTIONS] SRC_PATH|- CONTAINER:DEST_PATH [flags]

有了JVM工具,我們就可以開始分析咯。

三查GC情況

通過jstat查看gc情況

 bin/jstat -gcutil 1 1s

file

看樣子沒有什麼問題,full gc也少。再看一下對象的占用情況,由於是容器內部,進程號為1,執行如下命令:

bin/jmap -histo 1 |more 

發現ByteBuffer對象占用最高,這是異常點一。
file

四查線程快照情況
  • 通過jstack查看線程快照情況。
 bin/jstack -l 1 > thread.txt

下載快照,這裡推薦一個線上的線程快照分析網站。

https://gceasy.io

file

上傳後,發現創建的線程近2000個,且大多是TIMED_WAITING狀態。感覺逐漸接近真相了。 點擊詳情發現有大量的kafka-producer-network-thread | producer-X 線程。如果是低版本則是大量的ProducerSendThread線程。(後續驗證得知),可以看出這個是kafka生產者創建的線程,如下是生產者發送模型:

file

根據生產者的發送模型,我們知道,這個sender線程主要做兩個事,一是獲取kafka集群的Metadata共用給多個生產者,二是把生產者送到本地消息隊列中的數據,發送至遠端集群。而本地消息隊列底層的數據結構就是java NIO的ByteBuffer。

這裡發現了異常點二:創建過多kafka生產者。

由於沒有業務代碼,決定寫一個Demo程式來驗證這個想法,定時2秒創建一個生產者對象,發送當前時間到kafka中,為了更好的觀察,啟動時指定jmx埠,使用jconsole來觀察線程和記憶體情況,代碼如下:

nohup java -jar -Djava.rmi.server.hostname=ip 
 -Dcom.sun.management.jmxremote.port=18099
 -Dcom.sun.management.jmxremote.rmi.port=18099
 -Dcom.sun.management.jmxremote.ssl=false
 -Dcom.sun.management.jmxremote.authenticate=false -jar
 com.hyq.kafkaMultipleProducer-1.0.0.jar   2>&1 &

連接jconsole後觀察,發現線程數一直增長,使用記憶體也在逐漸增加,具體情況如下圖:

file

故障原因回顧

分析到這裡,基本確定了,應該是業務代碼中迴圈創建Producer對象導致的。
在kafka生產者發送模型中封裝了 Java NIO中的 ByteBuffer 用來保存消息數據,ByteBuffer的創建是非常消耗資源的,儘管設計了BufferPool來複用,但也經不住每一條消息就創建一個buffer對象,這也就是為什麼jmap顯示ByteBuffer占用記憶體最多的原因。

總結

在日常的故障定位中,多多使用JDK自帶的工具,來幫助我們輔助定位問題。一些其他的知識點:
jmap -histo顯示的對象含義:

[C 代表  char[]
[S 代表 short[]
[I 代表 int[]
[B 代表 byte[]
[[I 代表 int[][]

如果導出的dump文件過大,可以將MAT上傳至伺服器,分析完畢後,下載分析報告查看,命令為:

./mat/ParseHeapDump.sh active.dump  org.eclipse.mat.api:suspects
org.eclipse.mat.api:overview org.eclipse.mat.api:top_components

可能儘快觸發Full GC的幾種方式

1) System.gc();或者Runtime.getRuntime().gc();

2 ) jmap -histo:live或者jmap -dump:live。
這個命令執行,JVM會先觸發gc,然後再統計信息。
3) 老生代記憶體不足的時候
 

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 本周的 上分享了一篇小文章,它裡面提到的冷知識很有意思,我稍作補充,分享給大家。 它提到的部分問題,讀者們可以先思考下: 若兩個元組相等,即 a==b 且 a is b,那麼相同索引的元素(如 a[0] 、b[0])是否必然相等呢? 若兩個對象的 hash 結果相等,即 hash(a) == has ...
  • JDK(Java Development Kit) JDK顧名思義就是Java開發工具包,是Sun Microsystems針對Java開發員的產品,是Java程式員通過Java語言編寫程式所需的開發工具包,JDK包含了JRE,同時還包含了編譯Java源碼的編輯器Javac,還包含了很多Java程式 ...
  • 什麼是 PHP 擴展 通俗說,PHP 擴展是增強 PHP 語言功能的插件。PHP 提供了編程語言的語法,比如分支、迴圈、函數、類等,這些是 PHP 本身所提供的。在某些情況下需要在 PHP 語言的基礎上進行擴展,那麼就需要通過 PHP 底層提供的數據結構和介面來開發 PHP 擴展,從而來補充或擴展 ...
  • 聲明 :本博客僅僅是一個初學者的學習記錄、心得總結,其中肯定有許多錯誤,不具有參考價值,歡迎大佬指正,謝謝!想和我交流、一起學習、一起進步的朋友可以加我微信Liu__66666666 這是簡單學習一遍之後的記錄,後期還會修改。 一、學習內容 1. "jvm簡介" 2. 記憶體模型 3. 垃圾回收機制 ...
  • 恢復內容開始 目錄 1. 分支結構 1.1 初步介紹 1.2 使用案例 1.3 練習 2.迴圈結構 1.1 初步介紹 1.2 使用案例 目錄 1. 分支結構 1.1 初步介紹 1.2 使用案例 1.3 練習 2.迴圈結構 1.1 初步介紹 1.2 使用案例 1. 分支結構 1.1 初步介紹 1.2 ...
  • ZooKeeper技術的極少以及ZooKeeper集群的搭建 ...
  • 0. 序 我從一生下來就呆在這個昏暗的地方。 我不明白為什麼程式員這麼喜歡 Dark Mode,Brighten Mode 才是我的最愛。聽說最近連 iphone 都開始支持 Dark Mode 了,沒話講。。。說好的絕不妥協呢? 我周圍是熙熙攘攘的函數群,穿插著變數聲明和巨集定義。 在我們這裡,函數 ...
  • 一、前言 應聘IC前端相關崗位時,FIFO是最常考也是最基本的題目。FIFO經常用於數據緩存、位寬轉換、非同步時鐘域處理。隨著晶元規模的快速增長,靈活的system verilog成為設計/驗證人員的基本功。本文從簡易版的同步FIFO開始,熟悉IP設計與驗證的基礎技能。 二、IP設計 FIFO這一IP ...
一周排行
    -Advertisement-
    Play Games
  • .Net8.0 Blazor Hybird 桌面端 (WPF/Winform) 實測可以完整運行在 win7sp1/win10/win11. 如果用其他工具打包,還可以運行在mac/linux下, 傳送門BlazorHybrid 發佈為無依賴包方式 安裝 WebView2Runtime 1.57 M ...
  • 目錄前言PostgreSql安裝測試額外Nuget安裝Person.cs模擬運行Navicate連postgresql解決方案Garnet為什麼要選擇Garnet而不是RedisRedis不再開源Windows版的Redis是由微軟維護的Windows Redis版本老舊,後續可能不再更新Garne ...
  • C#TMS系統代碼-聯表報表學習 領導被裁了之後很快就有人上任了,幾乎是無縫銜接,很難讓我不想到這早就決定好了。我的職責沒有任何變化。感受下來這個系統封裝程度很高,我只要會調用方法就行。這個系統交付之後不會有太多問題,更多應該是做小需求,有大的開發任務應該也是第二期的事,嗯?怎麼感覺我變成運維了?而 ...
  • 我在隨筆《EAV模型(實體-屬性-值)的設計和低代碼的處理方案(1)》中介紹了一些基本的EAV模型設計知識和基於Winform場景下低代碼(或者說無代碼)的一些實現思路,在本篇隨筆中,我們來分析一下這種針對通用業務,且只需定義就能構建業務模塊存儲和界面的解決方案,其中的數據查詢處理的操作。 ...
  • 對某個遠程伺服器啟用和設置NTP服務(Windows系統) 打開註冊表 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\NtpServer 將 Enabled 的值設置為 1,這將啟用NTP伺服器功 ...
  • title: Django信號與擴展:深入理解與實踐 date: 2024/5/15 22:40:52 updated: 2024/5/15 22:40:52 categories: 後端開發 tags: Django 信號 松耦合 觀察者 擴展 安全 性能 第一部分:Django信號基礎 Djan ...
  • 使用xadmin2遇到的問題&解決 環境配置: 使用的模塊版本: 關聯的包 Django 3.2.15 mysqlclient 2.2.4 xadmin 2.0.1 django-crispy-forms >= 1.6.0 django-import-export >= 0.5.1 django-r ...
  • 今天我打算整點兒不一樣的內容,通過之前學習的TransformerMap和LazyMap鏈,想搞點不一樣的,所以我關註了另外一條鏈DefaultedMap鏈,主要調用鏈為: 調用鏈詳細描述: ObjectInputStream.readObject() DefaultedMap.readObject ...
  • 後端應用級開發者該如何擁抱 AI GC?就是在這樣的一個大的浪潮下,我們的傳統的應用級開發者。我們該如何選擇職業或者是如何去快速轉型,跟上這樣的一個行業的一個浪潮? 0 AI金字塔模型 越往上它的整個難度就是職業機會也好,或者說是整個的這個運作也好,它的難度會越大,然後越往下機會就會越多,所以這是一 ...
  • @Autowired是Spring框架提供的註解,@Resource是Java EE 5規範提供的註解。 @Autowired預設按照類型自動裝配,而@Resource預設按照名稱自動裝配。 @Autowired支持@Qualifier註解來指定裝配哪一個具有相同類型的bean,而@Resourc... ...