[转帖]限制容器中的jvm

限制,容器,jvm · 浏览次数 : 0

小编点评

**1. 设置容器的限制** - 不要手动设置jvm堆空间,而是设置容器的限制。 - 容器的限制可以实现容器(cgroups)的基本目标:隔离进程集合的资源使用。 - 设置容器限制可以实现容器(cgroups)的基本目标:隔离进程集合的资源使用。 **2. 设置JVM的限制** - 在容器环境中,由于java获取不到容器的内存限制,只能获取到服务器的配置,所以这样容易引起不必要的问题。 - 可以通过`-Xmx`或`MaxRAM`等参数设置jvm内存限制。 **3. 实践** **对容器的资源进行限制** - 在Dockerfile中,在java应用的启动命令中加入`-XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0`等参数,其中75.0表示将JVM的`MaxHeapSize`设置为容器内存的75%。 **对JVM资源进行限制** - 在Dockerfile中,在java应用的启动命令中加入`-XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0`等参数,其中75.0表示将JVM的`MaxHeapSize`设置为容器内存的75%。

正文

rancher中部署完java应用之后,需要对java程序的jvm进行设置,这个非常重要,不然可能会引起比较严重的后果:容器无限制的重启或者主机的内存被耗尽。

在开始之前,先来看一个问题:

在容器中跑了一个java应用,那怎么来限制这个jvm的memory呢?

按照传统的思路对memory进行限制:
首先java应用的jvm内存限制可以通过-Xmx进行限制,容器的内存限制也是可以设置的,特别是对于kubernetes的容器,可以通过resource request/limit来设置一个memory可以使用的范围。

如此一来,jvm中的memory如果只设定成一个固定的数值就显得非常不灵活了。如果jvm可以自动的识别容器的可用memory的话就好了,这样的话,如果我希望调大jvm内存,只需要改变容器的memory limit的定义就可以了,不用再调整java应用的jvm参数值了。

带着这个问题,继续往下看。

一、设置容器的限制

首先明确一点:不要为在容器中运行的任何java程序手动设置jvm堆空间,而是要设置容器的限制。

那到底是为什么呢?

  • 首先,设置容器限制可以实现容器(cgroups)的基本目标:隔离进程集合的资源使用。例如,当通过JVM参数手动分配空间时,可能完全忽视了容器的限制。
  • 它允许轻松调整容器的资源分配。例如,应用需要更多的内存的时候,我们只需要把容器的资源限制调大就行,而无需修改容器中JVM的参数。
  • 在容器编排环境(例如Kubernetes)中运行,则容器限制对于节点运行状况和调度都将变得极为重要。调度程序将使用这些限制来找到合适的节点来运行容器,并确保相等的负载分布在各个节点上。如果通过JVM参数设置内存使用率,则此信息对于调度程序不可用,因此调度程序不知道如何有效的分散容器的负载。
  • 如果未设置容器限制,并且Java应用在没有显式设置任何JVM内存标志的容器中运行,则JVM会自动将最大堆设置为运行它的主机节点上RAM的1/4,。例如,如果容器在32G内存的主机节点上运行,则JVM进程堆空间可以最大为8G。如果在一个节点上运行10个容器,最大可能需要80G的堆内存,这样造成的后果就可想而知了。

二、设置JVM的限制

在容器环境中,由于java获取不到容器的内存限制,只能获取到服务器的配置,所以这样容易引起不必要的问题。例如,限制容器使用100M内存,但是jvm根据服务器配置来分配拟初始化内存,导致java进程超过容器限制被kill掉。为了解决这个问题,我们可以设置-Xmx或者MaxRAM来解决,但是这就跟刚开始讲的一样,非常不灵活。

为了解决这个问题,Java 10引入了+UseContainerSupport(默认情况下开启),通过这个特性,可以使得JVM在容器环境中分配合理的堆内存。并且在jdk8u191版本之后,这个功能引入到了JDK8,这对于jdk8的用户而言确实是一个很大利好,也可以说是大势所趋吧。

-XX:+UseContainerSupport允许JVM从主机读取cgroup限制,例如可用的CPU和RAM,并进行相应的配置。这样当JVM内存不够用时,会抛出OOM异常,就不会因为JVM超过容器的资源限制而使得容器被杀死了。

注意:在jdk8u191版本之后,-XX:{Min|Max}RAMFraction已经被弃用了,引入了-XX:MaxRAMPercentage,其值介于0.0到100.0直接,默认值为25.0。

三、实践

首先要保证我们的jdk版本是jdk8u191或者更高版本jdk8。

1、对容器的资源进行限制

这里直接在已有的项目上进行修改,由于UI用的是rancher,可以直接在UI中进行设置:

点击升级–>显示高级选项–>安全/主机设置,按照实际需求填写,我这里限制内存为1024M,限制CPU为1核。
在这里插入图片描述

这里还要注意一下:因为对容器的资源进行限制之后,java应用启动所花费的时间会变长,所以如果开启了健康检查的话,记得把时间改得略微长一点,不然就可能在你之前所设定的时间内服务还没完全启来的话,pod会无限的 重启。

然后点击升级即可。

2、对JVM资源进行限制

在Dockerfile中,在java应用的启动命令中加入-XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0,如下:

java -XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0 -jar /opt/app.jar --server.port=${port} --spring.profiles.active=${opt_active}
  • 1

其中的75.0表示将JVM的MaxHeapSize(最大堆内存)设置为容器内存的75%。

注意:这里如果设置成75%,要写成-XX:MaxRAMPercentage=75.0;如果设置成80%要,要写成-XX:MaxRAMPercentage=80.0。看出端倪了吧,重点就是在这个.0上。我之前写成75,运行java程序的时候就会报错:Improperly specified VM option 'MaxRAMPercentage=75'。网上搜索之后,发现这是个bug,需要在后面加上.0才行,具体见https://stackoverflow.com/questions/58171149/java-8-docker-improperly-specified-vm-option-initialrampercentage-xx

3、验证

完成上面的容器和JVM的资源限制之后,重新发布下这个java应用。

在验证之前,按照理算的话,JVM的最大堆内存应该=容器内存限制值*75%=1024*75%=768M

然后直接用jmap命令查看JVM的堆内存:
在这里插入图片描述

和预期的一样,现在的MaxHeapSize的值为768M。这样以后要扩大JVM的堆内存的话,就只要修改容器的内存限制值就可以了,MaxHeapSize的值会随之增大。

参考文章:
https://www.colabug.com/2019/1225/6769764/amp/
https://zhuanlan.zhihu.com/p/140849800
https://www.bbsmax.com/A/qVdeP3qE5P/
https://stackoverflow.com/questions/58171149/java-8-docker-improperly-specified-vm-option-initialrampercentage-xx

文章知识点与官方知识档案匹配,可进一步学习相关知识

与[转帖]限制容器中的jvm相似的内容:

[转帖]限制容器中的jvm

在rancher中部署完java应用之后,需要对java程序的jvm进行设置,这个非常重要,不然可能会引起比较严重的后果:容器无限制的重启或者主机的内存被耗尽。 在开始之前,先来看一个问题: 在容器中跑了一个java应用,那怎么来限制这个jvm的memory呢? 按照传统的思路对memory进行限制

[转帖]一文解决内核是如何给容器中的进程分配CPU资源的?

https://zhuanlan.zhihu.com/p/615570804 现在很多公司的服务都是跑在容器下,我来问几个容器 CPU 相关的问题,看大家对天天在用的技术是否熟悉。 容器中的核是真的逻辑核吗? Linux 是如何对容器下的进程进行 CPU 限制的,底层是如何工作的? 容器中的 thr

[转帖]Docker限制容器的资源

docker在默认运行容器的情况下,是不会对运行的容器进行资源限制的,在自己的实验环境的话是随便你怎么弄的,不过在生产中是一定会对docker运行的容器进行资源限制的,如果不限制的话在生产中会带来很多弊端的。例如当资源没有做限制时,资源用完了后会导致其他的容器无法运行,在生产中的话是会部署几十个或者

[转帖]kubernetes限制pod的cpu和内存

http://www.5ityx.com/cate100/45070.html kubernetes限制pod的cpu和内存 1、在创建容器的配置文件中指定 spec: containers: - image: gcr.io/google_containers/serve_hostname imag

[转帖]轻松快速地调整Kubernetes的CPU和内存

在Kubernetes中分配和管理CPU和内存资源可能很棘手,但也很容易。本文,我将向你展示什么是Kubernetes资源和限制以及如何管理它们。 本文的目标是简单–如何帮助你快速调整项目中的Kubernetes资源信息,主要通过三种方式: 1. 为容器和 Pod 分配CPU和内存资源 2. Res

[转帖]Docker系列--Docker设置系统资源限制及验证

https://www.cnblogs.com/caijunchao/p/13415386.html 1、限制容器的资源 默认情况下,容器没有资源限制,可以使用主机内核调度程序允许的尽可能多的给定资源。Docker提供了控制容器可以使用多少内存或CPU的方法,设置docker run命令的运行时配置

[转帖]Java 容器化的历史坑(史坑) - 资源限制篇

https://blog.mygraphql.com/zh/posts/cloud/containerize/java-containerize/java-containerize-resource-limit/ -XX:ActiveProcessorCount=$POD_CPU_LIMIT 由来

[转帖]docker 容器基础技术:linux cgroup 简介

https://cizixs.com/2017/08/25/linux-cgroup/ Linux cgroups 的全称是 Linux Control Groups,它是 Linux 内核的特性,主要作用是限制、记录和隔离进程组(process groups)使用的物理资源(cpu、memory、

[转帖]TiKV 缩容不掉如何解决?

TiKV节点缩容不掉,通常遇到的情况: 1、经常遇到的情况是:3个节点的tikv集群缩容肯定会一直卡着,因为没有新节点接受要下线kv的region peer。 2、另外就是除缩容tikv外,剩下的KV硬盘使用情况比较高,到达schedule.high-space-ratio=0.6的限制,导致该ti

[转帖]Linux—CPU核数、上下文切换介绍及pidstat等命令详解

https://www.jianshu.com/p/0ae0c1153c34 关注:CodingTechWork,一起学习进步。 引言 并发编程 并发编程的目的是为了改善串行程序执行慢问题,但是,并不是启动更多线程就能够让程序执行更快。因为在并发时,容易受到软硬件资源等限制,从而导致上下文切换慢,频