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

相关推荐
40kuai2 小时前
kubernetes中数据存储etcd
容器·kubernetes·etcd
敲上瘾2 小时前
Linux系统cgroups资源精细化控制基础
linux·测试工具·docker·压力测试·cgroups
Harvey_D4 小时前
【部署K8S集群】 1、安装前环境准备配置
云原生·容器·kubernetes
伊成4 小时前
Docker 部署 Nginx 完整指南
nginx·docker·容器
落日漫游5 小时前
K8s核心组件全解析
运维·docker·运维开发
江湖有缘9 小时前
【Docker项目实战】使用Docker部署Notepad轻量级记事本
docker·容器·notepad++
舒一笑9 小时前
Started TttttApplication in 0.257 seconds (没有 Web 依赖导致 JVM 正常退出)
jvm·spring boot·后端
BTU_YC10 小时前
docker compose部署mysql
mysql·adb·docker
Wezzer11 小时前
k8s单master部署
云原生·容器·kubernetes
搬砖的小熊猫11 小时前
JVM核心原理与实战优化指南
jvm