一次容器化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
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...