Kubernetes_pod_javajdk_动态JVM堆内存大小限制

网友投稿 448 2022-10-26

Kubernetes_pod_javajdk_动态JVM堆内存大小限制

Kubernetes_pod_javajdk_动态JVM堆内存大小限制

前言

示例yaml片段:

- name: test

image: test.com/test/test:test01

resources:

limits:

cpu: 1000m

memory: 1024Mi

requests:

cpu: 500m

memory: 500Mi

由于Docker容器本质是是宿主机上的一个进程,它与宿主机共享一个/proc目录,也就是说我们在容器内看到的/proc/meminfo,/proc/cpuinfo与直接在宿主机上看到的一致。也即,此容器认为自己的系统资源同样是12核CPU,96G内存。默认情况下,JVM的Max Heap Size是系统内存的1/4,也就是24G作为最大JVM堆内存出现了运行的容器感知的资源,与Kubernetes分配给它的资源的偏差,这种偏差可能会导致Java应用不断的重启。

如何解决呢?随着JAVA版本不同,有不同处理方法,如下图JVM参数进化史(图片来自网络):

JDK8版本低于131,在容器启动JAVA程序时,自行定义好与资源配额一致的-Xmx等参数。随着JDK版本的升级,容器感知的功能就内置于Java应用中了,java 8u131+和java 9+版本,需要开启2个参数:-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap ;如果JDK8的版本高于191,可以使用MaxRAMPercentage这种更智能化的参数来解决。以下介绍2个通用方法!

一、JDK 版本java 8u131+和java 9+

在容器设置jvm 环境变量 ,同时启用-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=1 参数。

在Dokerfile文件,设定环境变量,示例片段:

ENV JAVA_OPTS -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=1

参考示例start.sh如下:

#!/bin/sh

# 无限制内存大小(字节/MB)

unlimitM=9223372036854771712/1048576

# 获取k8s 限制内存设置值.

limitM=$(cat /sys/fs/cgroup/memory/memory.limit_in_bytes)

if [ $limitM -eq $unlimitM ]

then

#设置默认大小 512M

limitM=536870912/1048576

fi

# limitM限制内存大小乘以0.75,作为jvm 启动参数

limitUM= $limitM *(75/100)

test_cmd="xjava -Xms${ limitUM }m -Xmx${ limitUM }m"

for v in $@

do

#判断参数大于4个的情况

if [ ${#v} -ge 4 ]

then

if [ "${v:0:4}" == "-Xmx" || "${v:0:4}" == "-Xms" ]

then

continue

else

test_cmd ="$ test_cmd $v"

fi

else

test_cmd ="$ test_cmd $v"

fi

done

exec $ test_cmd

注:通过获取k8s 限制容器内存或CPU大小,通过脚本计算替换xms,xmx 参数,较灵活设定JVM 大小。

二、JDK 版本java 8u191+

jdk1.8.191 +JVM内存参数新增了MaxRAMPercentage、InitialRAMPercentage、MinRAMPercentage,为适配Docker容器并标记为deprecated。Docker容器模式下,我们可以给每个JVM实例所属的POD分配任意大小的内存上限。如上POD为1G内存,通用的启动脚本中指定80%(-XX:MaxRAMPercentage=80.0 -XX:InitialRAMPercentage=80.0 -XX:MinRAMPercentage=80.0)。那么服务就相当于设置了-Xmx819m -Xms819m。

示例制作Dockerfile集成阿里云arthas java分析工具、测试app.jar应用jar:

FROM openjdk:8-jre-alpine

RUN echo "> /etc/apk/repositories \

&& echo ">> /etc/apk/repositories \

&& apk update upgrade \

&& apk add --no-cache procps unzip curl bash tzdata \

&& ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \

&& echo "Asia/Shanghai" > /etc/timezone

ENV TERM=xterm

ENV.UTF-8

RUN mkdir -p /usr/local/apps

ADD ./app.jar /usr/local/apps/

WORKDIR /usr/local

RUN apk add --update ttf-dejavu && rm -rf /var/cache/apk/*

WORKDIR /usr/local

EXPOSE 80

ENTRYPOINT ["/sbin/tini", "--"]

CMD ["sh","-c","java -XX:MaxRAMPercentage=80.0 -XX:InitialRAMPercentage=80.0 -XX:MinRAMPercentage=80.0 -jar /usr/local/apps/app.jar"]

制作成容器镜像后,通过k8s 发布部署,依然POD限制资源为1核、1G,启动进入容器通过java 命令查看,设定是否生效:

#Kubectl exec -it test-apps sh -n default

##java 版本

/usr/local # java -version

openjdk version "1.8.0_212"

OpenJDK Runtime Environment (IcedTea 3.12.0) (Alpine 8.212.04-r0)

OpenJDK 64-Bit Server VM (build 25.212-b04, mixed mode)

# jinfo 查看参数值

/usr/local #jinfo -flag MaxRAMPercentage 7

-XX:MaxRAMPercentage=80.000000

#启动 java -jar arthas-boot.jar xx(pid)

[arthas@7]$ jvm

RUNTIME

MEMORY

--------------------------------------------------------------------------------

HEAP-MEMORY-USAGE      init : 859832320(820.0 MiB)

[memory in bytes]      used : 95071040(90.7 MiB)

committed : 831193088(792.7 MiB)

max : 831193088(792.7 MiB)

NO-HEAP-MEMORY-USAGE   init : 2555904(2.4 MiB)

[memory in bytes]      used : 145747616(139.0 MiB)

committed : 150364160(143.4 MiB)

max : -1(-1 B)

PENDING-FINALIZE-COUN  0

注:从arthas工具,可以看到内存 max 792.7MiB 跟预期结果一致。

第二方法比第一种方法更加灵活!

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:springMarchal集成xStream的完整示例代码
下一篇:固态硬盘的接口类型有哪些
相关文章

 发表评论

暂时没有评论,来抢沙发吧~