JVM感知docker容器内存资源限制

容器中的java程序无法感知docker的内存资源限制
[root@xm-phy-kvm-113-2 ~]# docker run -m 100MB openjdk:8u131 java -XshowSettings:vm -version
VM settings:
    Max. Heap Size (Estimated): 17.43G
    Ergonomics Machine Class: server
    Using VM: OpenJDK 64-Bit Server VM

openjdk version "1.8.0_131"
OpenJDK Runtime Environment (build 1.8.0_131-8u131-b11-2-b11)
OpenJDK 64-Bit Server VM (build 25.131-b11, mixed mode)

我设置了 100MB 的容器内存,但JVM 设置了17.3G 的最大堆?它很可能会导致内核在某个时候杀死JVM程序

[root@xm-phy-kvm-113-2 ~]# docker run -m 100MB openjdk:8u131 java   -XX:+UnlockExperimentalVMOptions   -XX:+UseCGroupMemoryLimitForHeap   -XshowSettings:vm -version
VM settings:
    Max. Heap Size (Estimated): 44.50M
    Ergonomics Machine Class: server
    Using VM: OpenJDK 64-Bit Server VM

openjdk version "1.8.0_131"
OpenJDK Runtime Environment (build 1.8.0_131-8u131-b11-2-b11)
OpenJDK 64-Bit Server VM (build 25.131-b11, mixed mode)
java服务无感知docker资源限制导致的问题

在K8s中Deployments配置资源限制和预留的时候,比如设置最大内存为100M。但是宿主机的总内存为80G,这时候Pod启动后会超出内存限制,被Deployments杀掉。但为了维护设置的副本数量又创建新的,如此反复。

原因是默认情况JVM默认最大堆空间为系统总内存的1/4,在容器中没有感知到集群为Pod设置的资源限制,而是按宿主机的内存算的,所以最终超过限制内存。

解决方案

解决思路有两种:

  • 按资源限制算好,在 Java 启动参数中设置堆内存大小,保证不超限制
  • 让JVM感知到容器资源限制,按这个值来分配内存

Java SE 8u131向后 和 JDK 9 都有参数支持:如下

-XX:+UnlockExperimentalVMOptions 
-XX:+UseCGroupMemoryLimitForHeap

但是如果资源限制默认分配1/4有点浪费,因为一般一个Pod就跑这一个主要进程,所以可以改下这个默认值,如下:

# 2 代表1/2
-XX:MaxRAMFraction=2

这样配置并不代表就是资源限制的1/2,因为除了堆内存还有其他堆外内存需要空间,所以实际值要远小于1/2。网上有人在测试环境设置1,代表100%,但是我试过之后还是超过资源限制了,所以选了2,实际需要根据情况决定。

Java 8u131及以上版本开始支持了Docker的cpu和memory限制。

cpu limit(默认支持)

即如果没有显式指定-XX:ParalllelGCThreads 或者 -XX:CICompilerCount, 那么JVM使用docker的cpu限制。如果docker有指定cpu limit,jvm参数也有指定-XX:ParalllelGCThreads 或者 -XX:CICompilerCount,那么以指定的参数为准。

memory limit

在java8u131+及java9,需要加上-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap才能使得Xmx感知docker的memory limit。

参数/版本 -XX:+UseCGroupMemoryLimitForHeap -XX:ActiveProcessorCount -XX:+UseContainerSupport
java9 experimental,默认false
java10 experimental,默认false -1
java11 移除 -1 product,默认true

参考链接:

链接:
https://segmentfault.com/a/1190000014142950

Java SE support for Docker CPU and memory limits

Running a JVM in a Container Without Getting Killed

让JVM感知K8s资源限制 - 简书

相关推荐
longlongqin2 小时前
JVM 内存结构?
jvm
m0_741768856 小时前
使用docker的小例子
运维·docker·容器
最新小梦9 小时前
Docker日志管理
运维·docker·容器
ZHOU西口10 小时前
微服务实战系列之玩转Docker(十五)
nginx·docker·微服务·云原生·swarm·docker swarm·dockerui
Joeysoda11 小时前
Java数据结构 时间复杂度和空间复杂度
java·开发语言·jvm·数据结构·学习·算法
有你的晚安._11 小时前
pod基本概念
kubernetes
18你磊哥11 小时前
java重点学习-JVM组成
java·开发语言·jvm
lgbisha11 小时前
828华为云征文|华为云Flexus X实例docker部署最新Appsmith社区版,搭建自己的低代码平台
低代码·docker·华为云
记得开心一点嘛11 小时前
在Linux系统上使用Docker部署javaweb项目
linux·运维·docker
蜜桃小阿雯13 小时前
JAVA开源项目 校园美食分享平台 计算机毕业设计
java·jvm·spring boot·spring cloud·intellij-idea·美食