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

相关推荐
二猛子5 小时前
Linux(Centos版本)中安装Docker
linux·docker·centos
记得开心一点嘛7 小时前
Docker compose 部署微服务项目(从0-1出发纯享版无废话)
docker·容器·eureka
张帅涛_6667 小时前
golang goroutine(协程)和 channel(管道) 案例解析
jvm·golang·go
猿小猴子7 小时前
在 Ubuntu24.04 LTS 上 Docker 部署英文版 n8n 和 部署中文版 n8n-i18n-chinese
docker·容器·n8n
io无心8 小时前
Docker绑定端口报错
运维·docker·容器
zxnbmk9 小时前
pod内部共享命名空间与k8s命名空间是一个东西吗?
云原生·容器·kubernetes·namespaces
碎梦归途9 小时前
23种设计模式-行为型模式之策略模式(Java版本)
java·开发语言·jvm·设计模式·策略模式·行为型模式
三个蔡9 小时前
Java求职者面试:从Spring Boot到微服务的技术深度探索
java·大数据·spring boot·微服务·kubernetes
sniper_fandc9 小时前
JVM(Java虚拟机)详解
java·开发语言·jvm