一、背景

为了便于理解,先简单介绍下我司的微服务。我司的微服务是以 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

其他配置组合如下:

  1. Xms == Xmx == resources.requests.memory == resources.limits.memory
    上文「个人理解」中的内容已经说过了,「Pod 中的容器」 中不单单只有 Java 程序,当 Java 启动的时候 Ta 所要占用的最大内存(Xmx)+ 其他应用要占用的内存 会超过 resources.limits.memory 这个限制,这样就会导致 K8s 陷入不断的重复杀掉 Pod 重启 Pod 这个死循环里。
  2. Xms == Xmx > resources.requests.memory
    如此设置会造成一定资源的浪费,因为 Java 程序根本没机会跑到 resources.requests.memory 指定的内存大小,当 Java 程序超过了 Xmx 的时候就已经 OOM 了。
  3. 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 程序不会吃掉当前节点上的所有内存,进而影响其他应用的正常运行。

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐