linux cpu占用率如何看
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小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~