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

相关推荐
热爱学习的小怪兽18 分钟前
Docker容器的一些总结
运维·docker·容器
❀͜͡傀儡师1 小时前
Docker一键部署Nexus Terminal,高颜值SSH新体验
docker·容器·ssh
TH_12 小时前
腾讯云-(10)-宝塔面板-Docker下安装Elasticsearch
elasticsearch·docker·容器
面对疾风叭!哈撒给3 小时前
Docker之 Portainer、Node-RED和EMQX安装与配置
运维·docker·容器
kbirdg3 小时前
告别卡顿!内网服务器如何“优雅”地搬运 Docker 镜像?除了 docker save,你该试试这几招
docker
小吃饱了3 小时前
docker制作镜像
运维·docker·容器
Radan小哥4 小时前
Docker学习笔记—day008
笔记·学习·docker
哥哥还在IT中4 小时前
Docker的Cgroup Driver设置为Cgroupfs 和 Systemd 的区别
运维·docker·容器
java_logo4 小时前
LobeHub Docker 容器化部署指南
运维·人工智能·docker·ai·容器·ai编程·ai写作
qinyia5 小时前
WisdomSSH解决因未使用Docker资源导致的磁盘空间不足问题
运维·服务器·人工智能·后端·docker·ssh·github