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资源限制 - 简书

相关推荐
工业3D_大熊1 小时前
3D可视化引擎HOOPS Luminate场景图详解:形状的创建、销毁与管理
java·c++·3d·docker·c#·制造·数据可视化
szc17671 小时前
docker 相关命令
java·docker·jenkins
CP-DD1 小时前
Docker 容器化开发 应用
运维·docker·容器
Stark-C1 小时前
万物皆可Docker,在NAS上一键部署最新苹果MacOS 15系统
macos·docker·策略模式
老司机张师傅1 小时前
【微服务实战之Docker容器】第七章-Dockerfile解析
容器·dockerfile·虚悬镜像·docker学习
微信-since811922 小时前
[ruby on rails] 安装docker
后端·docker·ruby on rails
登云时刻2 小时前
Kubernetes集群外连接redis集群和使用redis-shake工具迁移数据(一)
redis·kubernetes·bootstrap
吴半杯3 小时前
gateway漏洞(CVE-2022-22947)
docker·kubernetes·gateway
今天我刷leetcode了吗3 小时前
docker 配置同宿主机共同网段的IP 同时通过通网段的另一个电脑实现远程连接docker
tcp/ip·docker·电脑
lwprain4 小时前
常用docker应用部署,wordpress、mysql、tomcat、nginx、redis
mysql·docker·tomcat