java jar killed_容器中Java 程序OOMKilled原因浅析
背景:
業(yè)務(wù)的容器化剛剛搞完,線上開始告警,容器重啟,容器重啟。describe pod 查看原因是OOMKilled
分析:
OOMKilled 是pod 中的進程使用的內(nèi)存超過了.spec.containers[*].resources.limits.memory中定義的內(nèi)存限制,在超出限制后, kubernetes 會向容器中的進程(pid=1)發(fā)送kill -9 信號。kill -9 信號對于進程來說是不可捕捉的,進程無法在收到-9 信號后優(yōu)雅的退出。 這對于業(yè)務(wù)來說是有損的。那么為啥進程會超過容器的limit 限制呢?
查看容器中進程的啟動參數(shù):
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
進程沒有設(shè)置內(nèi)存限制,但是這個業(yè)務(wù)之前在虛擬機上運行時,配置相同,啟動參數(shù)也是如此,為什么上線到容器中會經(jīng)常出現(xiàn)OOMKilled 的情況呢。這里就需要說到docker對進程資源的限制。
docker 通過 cgroup 來控制容器使用的資源配額,包括 CPU、內(nèi)存、磁盤三大方面,基本覆蓋了常見的資源配額和使用量控制。但是在java 的早期版本中(小于1.8.131),不支持讀取cgroup的限制。 默認是從/proc/目錄讀取可用內(nèi)存。但是容器中的/proc目錄默認是掛載的宿主機的內(nèi)存目錄。即java 讀取的到可用的內(nèi)存是宿主機的內(nèi)存。那么自然會導(dǎo)致進程超出容器limit 限制的問題。
驗證:
起初, 我們采用為進程設(shè)置-Xmx參數(shù)來限制進程的最大heap(堆)內(nèi)存。例如。 容器的limit限制為3G。 那么設(shè)置java進程的最大堆內(nèi)存為2.8G,采用這種方式后,容器重啟的情況少了很多,但還是偶爾會出現(xiàn)OOMKilled 的情況。因為-xms 只能設(shè)置java進程的堆內(nèi)存。 但是其他非堆內(nèi)存的占用一旦超過預(yù)留的內(nèi)存。還是會被kubernetes kil掉。附j(luò)ava 內(nèi)存結(jié)構(gòu):
JVM內(nèi)存結(jié)構(gòu)主要有三大塊:堆內(nèi)存、方法區(qū)和棧
堆內(nèi)存是JVM中最大的一塊由年輕代和老年代組成,而年輕代內(nèi)存又被分成三部分,Eden空間、From Survivor空間、To Survivor空間,默認情況下年輕代按照8:1:1的比例來分配;
方法區(qū)存儲類信息、常量、靜態(tài)變量等數(shù)據(jù),是線程共享的區(qū)域,為與Java堆區(qū)分,方法區(qū)還有一個別名Non-Heap(非堆);
棧又分為java虛擬機棧和本地方法棧主要用于方法的執(zhí)行。
那么有沒有辦法能讓java 正確識別容器的內(nèi)存限制呢?這里有三種方法:
升級java版本。Java 10支持開箱即用的容器,它將查找linux cgroup信息。這允許JVM基于容器限制進行垃圾收集。默認情況下使用標志打開它。
-XX:+UseContainerSupport
值得慶幸的是,其中一些功能已被移植到8u131和9以后??梢允褂靡韵聵酥敬蜷_它們。
-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap
LXCFS,FUSE filesystem for LXC是一個常駐服務(wù),它啟動以后會在指定目錄中自行維護與上面列出的/proc目錄中的文件同名的文件,容器從lxcfs維護的/proc文件中讀取數(shù)據(jù)時,得到的是容器的狀態(tài)數(shù)據(jù),而不是整個宿主機的狀態(tài)。 這樣。java進程讀取到的就是容器的limit 限制。而不是宿主機內(nèi)存
-XX:MaxRAM=`cat /sys/fs/cgroup/memory/memory.limit_in_bytes` 通過MaxRAM 參數(shù)讀取默認的limit限制作為java 內(nèi)存的最大可用內(nèi)存。同時結(jié)合-Xmx 設(shè)置堆內(nèi)存大小
總結(jié)
以上是生活随笔為你收集整理的java jar killed_容器中Java 程序OOMKilled原因浅析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java刷卡机_JavaPOS
- 下一篇: java fx choicebox_Ja