当 K8s资源管理 与 JVM参数(Xms、Xmx)相遇
K8s 资源管理 JVM Xms Xmx
一、背景
为了便于理解,先简单介绍下我司的微服务。我司的微服务是以 Pod 的方式投递到 K8 环境中。Pod 中运行的是一个 springboot 项目。该项目是通过 Java 的 jar 命令来启动的,启动的同时设置了相关的 Xms 和 Xmx 等参数,如下:
jar -Xms$XMS -Xmx$XMX -Xmn$XMN /springboot-xxx.jar
对于 Pod 我们也做了一些相关的资源限制,如下:
二、一些个人理解
在实际工作当中,由于 JVM 的 Xms、Xmx 和 Pod 的 resources.requests.memory、resources.limits.memory 都与内存相关,有一定的相关性,如果设置不好会出现一些问题。所以,如何设置,设置多大就成了不大不小的问题。
这里,我想强调下:
我这里只想提供一个较为无脑的通用配置方案,但在实际工作当中,还需要根据具体的情况具体设置。
在具体说配置原则之前,先说下我对 JVM 和 Pod 之间关系的理解:
首先通过 K8s 资源管理,圈定「Pod 中的容器」的资源范围,我们可以将这个过程视为攒一台指定配置(CPU、MEMORY)的电脑,我把 「Pod 中的容器」 类比为一台电脑,JVM 是一个运行在这台电脑上(Pod 中的容器)上的应用。为了保证这个电脑(Pod 中的容器)能够正常运行,其实还有很多无需我们关注的一些其他应用在运行。
通过,上边的理解,得出以下结论:
电脑(Pod 中的容器)的实际占用的内存 == JVM 占用的内存 + 其他应用占用的内存
三、通用配置方案
我先把最终的通用配置方案抛出来,然后通过列出其他配置方案出现的问题,来说明为啥要这样,如下:
Xms == Xmx == resources.requests.memory < resources.limits.memory
其他配置组合如下:
- Xms == Xmx == resources.requests.memory == resources.limits.memory
上文「个人理解」中的内容已经说过了,「Pod 中的容器」 中不单单只有 Java 程序,当 Java 启动的时候 Ta 所要占用的最大内存(Xmx)+ 其他应用要占用的内存 会超过 resources.limits.memory 这个限制,这样就会导致 K8s 陷入不断的重复杀掉 Pod 重启 Pod 这个死循环里。 - Xms == Xmx > resources.requests.memory
如此设置会造成一定资源的浪费,因为 Java 程序根本没机会跑到 resources.requests.memory 指定的内存大小,当 Java 程序超过了 Xmx 的时候就已经 OOM 了。 - Xms == Xmx > resources.limits.memory
当 Java 程序启动的时候需要 Xmx 大小的内存,假设节点内存充足,Java 程序能够拿到了这些内存进行启动。作为「Pod 中的容器」最主要的应用,Java 程序获取的内存大小(Xmx) 已经超过 resources.limits.memory 这限制。所以,K8s 会直接杀死整个 Pod 然后尝试重启,此后将会陷入一个杀死重启的死循环当中。
这里 resources.requests.memory 可以理解为这些内存资源基本保证 Java 程序的日常运行。当 Java 程序某一时刻由于突发情况需要更多内存的时候(例如:并发高峰,定时任务等),此时, resources.limits.memory 参数将保证,该 Java 程序不会吃掉当前节点上的所有内存,进而影响其他应用的正常运行。
更多推荐
所有评论(0)