当前位置 博文首页 > noah-罗:K8S(18)容器环境下资源限制与jvm内存回收

    noah-罗:K8S(18)容器环境下资源限制与jvm内存回收

    作者:noah-罗 时间:2021-04-30 18:17

    K8S(18)容器环境下资源限制与jvm内存回收

    目录
    • K8S(18)容器环境下资源限制与jvm内存回收
      • 一、k8s中的java资源限制与可能的问题
        • 方案1:通过JVM的Xms和Xmx参数限制
        • 方案2:通过容器的requests和limits参数控制
        • 方案3:容器参数和JVM参数共用
      • 二、解决问题三板斧
        • 1)采用JDK8-191以上的jdk版本
        • 2)使用JVM新的资源限制参数且不相等
        • 3)配置容器的资源限制参数

    一、k8s中的java资源限制与可能的问题

    与以前单机跑单服务的情况相比,在k8s、docker容器化环境下的宿主机内存、cpu相对更大,所以当运行java类程序的时候,就必然有必要对容器进行内存限制,否则以java默认参数启动,一个程序就可能吃掉你四分之一的内存

    但是怎么限制,就是一个值得考虑的问题了。

    方案1:通过JVM的Xms和Xmx参数限制

    java -Xms2048m -Xmx2048m -jar register.jar
    

    在非容器化时,最常规的方案;在容器化中,也经常使用向容器传递环境变量的方式,通过控制这两个参数来控制服务的内存使用量

    在网上通常的jvm调优方案中,也通常会要求把这两个参数设置为相等(可认为属于调优共识),来较小FGC的频率和提高性能

    但是在容器化情况下(假设xmx=xms=4G),存在的问题是:

    A 内存不释放问题:

    1. java容器运行后,会慢慢的用到设置的内存上限4G
    2. 由于还有其他的开销,一般会达到6G左右,并且不会释放
    3. 你会发现你宿主机或集群的内存,只升高不降低,除非你重启容器

    B 参数设置多少的问题:

    1. 由于给它设置的内存,它总会用完,不好确定到底给它多少内存
    2. 给多了不够用,给少了GC频繁
    3. 有些人要说GC调优确定最合适内存,但这个因素不可控

    所以这样,宿主机或集群的总内存,必须得大于你设置的所有容器的内存上限总和才保险

    方案2:通过容器的requests和limits参数控制

    docker容器和k8s都可以通过参数限制分配给容器的内存大小,同样假设分配了4G,问题会是

    1. 容器资源隔离的原因,容器中看到的内存大小=宿主机的内存大小
    2. 容器中的java服务,不知道自己被限制了内存,会按默认的1/4申请内存
    3. 由于对容器进行了内存限制,所以极大概率该容器运行一段时间后会被重启

    方案3:容器参数和JVM参数共用

    较可行的方案是两边的参数一起使用,只是要注意容器限制的内存要比jvm设置的大(1-2)G,因为前面说了JVM设置的4G,实际可能会用到6G。

    但是共用也没有彻底解决第一个方案中的问题,即:

    1. 给java服务到底分配多少内存
    2. 申请的内存不释放,导致宿主机内存总量上限问题
    3. 多个地方设置内存参数,麻烦

    二、解决问题三板斧

    主要参考的三个博客
    参考1:https://www.cnblogs.com/xiaoqi/p/container-jvm.html
    参考2:https://www.imooc.com/article/292785?block_id=tuijian_wz
    参考3:https://blog.csdn.net/qq_40378034/article/details/110677269

    1)采用JDK8-191以上的jdk版本

    由于jdk8-191以前的jdk版本,是不能感知到自己是在容器中运行的,所以对容器设置的资源限制,java程序不能感知,因此会按宿主机的总内存来申请资源

    2)使用JVM新的资源限制参数且不相等

    java -XX:MaxRAMPercentage=90.0 -XX:MinRAMPercentage=60.0 -jar register.jar
    

    [MAX|MIN]RAMPercentage参数,是191版本后新增加的参数,该参数可以感知容器的资源限制,并以此限制为申请的最大最小资源量,即Xms和Xmx

    由参考文章3中的结论:Xms和Xmx不相等时,在可能的情况下,GC过程会慢慢释放内存回操作系统,而我们 设置的[MAX|MIN]RAMPercentage这两个参数不等,达到的结果就是Xms和Xmx不相等

    # 此命令可以在容器中验证,java服务按此规则申请时,会申请的内存大小
    java -XX:+PrintFlagsFinal -XX:MaxRAMPercentage=90.0 -XX:MinRAMPercentage=60.0 -version | grep -Ei "heapsize|rampercentage"
    

    3)配置容器的资源限制参数

    在前两条的基础上,最后在配合容器的资源限制功能后,就能做到

    1. 限制容器的内存上限
    2. 容器内的jvm服务,能根据资源限制来申请内存
    3. 由于jvm会释放内存,所以可先设一个较大值,经过长期观察,可以确定该服务的常规内存水平
    4. 最终可以实现合理设置了容器、宿主机、java程序三者的内存的目的
    bk
    下一篇:没有了