容器中Java 程序OOMKilled原因淺析


背景:

業務的容器化剛剛搞完,線上開始告警,容器重啟,容器重啟。describe pod 查看原因是OOMKilled

分析:

OOMKilled 是pod 中的進程使用的內存超過了.spec.containers[*].resources.limits.memory中定義的內存限制,在超出限制后, kubernetes 會向容器中的進程(pid=1)發送kill -9 信號。kill -9 信號對於進程來說是不可捕捉的,進程無法在收到-9 信號后優雅的退出。 這對於業務來說是有損的。那么為啥進程會超過容器的limit 限制呢?
查看容器中進程的啟動參數:

java -Dfile.encoding=UTF-8 -Duser.timezone=Asia/Shanghai -XX:MetaspaceSize=128m -jar bxr-web-1.0.jar

查看容器的limit限制

k8s-master-01#kubectl get pods -n calculation bxr-web-dd656458b-8m4fb -o=custom-columns=name:.metadata.name,namespace:.metadata.namespace,memory-limit:.spec.containers[0].resources.limits.memory


name                      namespace     memory-limit
bxr-web-dd656458b-8m4fb   calculation   2000Mi

進程沒有設置內存限制,但是這個業務之前在虛擬機上運行時,配置相同,啟動參數也是如此,為什么上線到容器中會經常出現OOMKilled 的情況呢。這里就需要說到docker對進程資源的限制。

docker 通過 cgroup 來控制容器使用的資源配額,包括 CPU、內存、磁盤三大方面,基本覆蓋了常見的資源配額和使用量控制。但是在java 的早期版本中(小於1.8.131),不支持讀取cgroup的限制。 默認是從/proc/目錄讀取可用內存。但是容器中的/proc目錄默認是掛載的宿主機的內存目錄。即java 讀取的到可用的內存是宿主機的內存。那么自然會導致進程超出容器limit 限制的問題。
驗證:

起初, 我們采用為進程設置-Xmx參數來限制進程的最大heap(堆)內存。例如。 容器的limit限制為3G。 那么設置java進程的最大堆內存為2.8G,采用這種方式后,容器重啟的情況少了很多,但還是偶爾會出現OOMKilled 的情況。因為-xms 只能設置java進程的堆內存。 但是其他非堆內存的占用一旦超過預留的內存。還是會被kubernetes kil掉。附java 內存結構:
image

JVM內存結構主要有三大塊:堆內存、方法區和棧

堆內存是JVM中最大的一塊由年輕代和老年代組成,而年輕代內存又被分成三部分,Eden空間、From Survivor空間、To Survivor空間,默認情況下年輕代按照8:1:1的比例來分配;

方法區存儲類信息、常量、靜態變量等數據,是線程共享的區域,為與Java堆區分,方法區還有一個別名Non-Heap(非堆);

棧又分為java虛擬機棧和本地方法棧主要用於方法的執行。

那么有沒有辦法能讓java 正確識別容器的內存限制呢?這里有三種方法:

  1. 升級java版本。Java 10支持開箱即用的容器,它將查找linux cgroup信息。這允許JVM基於容器限制進行垃圾收集。默認情況下使用標志打開它。
-XX:+UseContainerSupport

值得慶幸的是,其中一些功能已被移植到8u131和9以后。可以使用以下標志打開它們。

-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap
  1. LXCFS,FUSE filesystem for LXC是一個常駐服務,它啟動以后會在指定目錄中自行維護與上面列出的/proc目錄中的文件同名的文件,容器從lxcfs維護的/proc文件中讀取數據時,得到的是容器的狀態數據,而不是整個宿主機的狀態。 這樣。java進程讀取到的就是容器的limit 限制。而不是宿主機內存
  2. -XX:MaxRAM=`cat /sys/fs/cgroup/memory/memory.limit_in_bytes` 通過MaxRAM 參數讀取默認的limit限制作為java 內存的最大可用內存。同時結合-Xmx 設置堆內存大小


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM