首页 > 系统相关 >云原生背景下如何配置 JVM 内存

云原生背景下如何配置 JVM 内存

时间:2023-05-15 10:11:44浏览次数:45  
标签:原生 容器 JVM 内存 应用 k8s CPU

image.png

背景

前段时间业务研发反馈说是他的应用内存使用率很高,导致频繁的重启,让我排查下是怎么回事;

在这之前我也没怎么在意过这个问题,正好这次排查分析的过程做一个记录。

首先我查看了监控面板里的 Pod 监控:
WeChatWorkScreenshot_ac6f8d80-bdb4-469e-af1a-b2199c9ee288.png

发现确实是快满了,而此时去查看应用的 JVM 占用情况却只有30%左右;说明并不是应用内存满了导致 JVM 的 OOM,而是 Pod 的内存满了,导致 Pod 的内存溢出,从而被 k8s 杀掉了。

k8s 为了维持应用的副本数量就得重启一个 Pod,所以看起来就是应用运行一段时间后就被重启。


WeChatWorkScreenshot_6213e2f8-c429-4d33-acdd-e639275dd92b.png
而这个应用配置的是 JVM 8G,容器申请的内存是16G,所以 Pod 的内存占用看起来也就 50% 左右。

容器的原理

在解决这个问题之前还是先简单了解下容器的运行原理,因为在 k8s 中所有的应用都是运行在容器中的,而容器本质上也是运行在宿主机上的一个个经常而已。

但我们使用 Docker 的时候会感觉每个容器启动的应用之间互不干扰,从文件系统、网络、CPU、内存这些都能完全隔离开来,就像两个运行在不同的服务器中的应用。

其实这一点也不是啥黑科技,Linux 早就支持 2.6.x 的版本就已经支持 namespace 隔离了,使用 namespace 可以将两个进程完全隔离。

仅仅将资源隔离还不够,还需要限制对资源的使用,比如 CPU、内存、磁盘、带宽这些也得做限制;这点也可以使用 cgroups 进行配置。

它可以限制某个进程的资源,比如宿主机是 4 核 CPU,8G 内存,为了保护其他容器,必须给这个容器配置使用上限:1核 CPU,2G内存。

image.png

这张图就很清晰的表示了 namespacecgroups 在容器技术中的作用,简单来说就是:

  • namespace 负责隔离
  • cgroups 负责限制

在 k8s 中也有对应的提现:

  resources:
    requests:
      memory: 1024Mi
      cpu: 0.1
    limits:
      memory: 1024Mi
      cpu: 4

这个资源清单表示该应用至少需要为一个容器分配一个 0.1 核和 1024M 的资源,CPU 的最高上限为 4 个核心。

不同的OOM

回到本次的问题,可以确认是容器发生了 OOM 从而导致被 k8s 重启,这也是我们配置 limits 的作用。

k8s 内存溢出导致容器退出会出现 exit code 137 的一个 event 日志。

因为该应用的 JVM 内存配置和容器的配置大小是一样的,都是8GB,但 Java 应用还有一些非 JVM 管理的内存,比如堆外内存之类的,这样很容易就导致容器内存大小超过了限制的 8G 了,也就导致了容器内存溢出。

云原生背景的优化

因为这个应用本身使用的内存不多,所以建议将堆内存限制到 4GB,这样就避免了容器内存超限,从而解决了问题。

当然之后我们也会在应用配置栏里加上建议:推荐 JVM 的配置小于容器限制的 2/3,预留一些内存。

其实本质上还是开发模式没有转变过来,以传统的 Java 应用开发模式甚至都不会去了解容器的内存大小,因为以前大家的应用都是部署在一个内存较大的虚拟机上,所以感知不到容器内存的限制。

从而误以为将两者画了等号,这一点可能在 Java 应用中尤为明显,毕竟多了一个 JVM;甚至在老版本的 JDK 中如果没有设置堆内存大小,无法感知到容器的内存限制,从而自动生成的 Xmx 大于了容器的内存大小,以致于 OOM。

标签:原生,容器,JVM,内存,应用,k8s,CPU
From: https://www.cnblogs.com/crossoverJie/p/17401011.html

相关文章

  • 「硬核JS」你的程序中可能存在内存泄漏
    写在前面想来很多同学看到内存泄漏,内心直接会跳出两个字:闭包!!!再让你说点其它的估计就噤声了。如果你对内存泄漏的了解仅限于闭包,那真的是应该仔细看此文了,闭包可能会造成内存泄漏,但是内存泄漏并不是只有闭包,它只是内存泄漏的引子之一罢了。写的程序运行一段时间后慢慢变卡甚至要......
  • c# can总线开发接口源代码,完美解决内存溢出,程序闪退问题,可放心使用。
    c#can总线开发接口源代码,完美解决内存溢出,程序闪退问题,可放心使用。另本示例中还有TCPClient,串口连接源代码,供给有需要的人学习。ID:4830648911771998......
  • vector传递内存参数的三种方式
    vector作为参数的三种传参方式c++中常用的vector容器作为参数时,有三种传参方式,分别如下(为说明问题,用二维vector):function1(std::vector<std::vector<int>>vec),传值function2(std::vector<std::vector<int>>&vec),传引用function3(std::vector<std::vector<int>>*ve......
  • 5-1liunx虚拟机内存分配
    一、虚拟机硬件配置1.CPU:2核或更多2.内存:1G以上,推荐2G。3.硬盘:一块硬盘,200G。4.网卡:NAT模式。5.光盘:挂载对应版本的ISO文件。二、ISO下载地址:Centos http://mirrors.aliyun.com http://mirrors.sohu.com http://mirrors.163.comUbuntu https://cdimage.ubuntu.com......
  • 数据结构-二维数组内存结构
    二维数组内存结构  逻辑上是二维的,再分配内存的时候,也是给他分配一维的内存行优先存储 行优先存储,M行N列的b[i][j]的存储地址=基地址+(i*N+j)*sizeof(ElemType)列优先存储 M行N列b[i][j]的存储地址=基地址+(j*M+i)*sizeof(ElemType)......
  • string传递内存参数
    使用string作为函数参数内存的输入使用string传递和获取内存不需要考虑内存释放在C++中,使用std::string类型进行字符串的传递和获取不需要显式考虑内存释放的原因是,std::string类实现了自动内存管理。std::string类封装了对字符串内存的分配和释放操作,它负责在构......
  • 操作系统:为什么一个页表项通常占用1Byte,1字节呢?页表项≠逻辑地址!常见OS内存管理误区辨
    为什么一个页表项通常占用1Byte,1字节呢?页表项≠逻辑地址!如果还不懂,请看:页目录、页表和页三者的关系详解每个页表项占用一个字节是怎么来的?问题启发一开始是做题的时候,为什么不是2^12bit,而是2^12Byte某计算机主存按节址,逻地址和物理地址都是32位页表项大小为4B。请回......
  • 深入理解 JVM —— 类加载及执行子系统案例
    Tomcat——正统的类加载器结构为一个功能健全的Web服务器,都要解决如下的这些问题:部署在同一个服务器上的 两个Web应用程序 所使用的 Java类库可以实现相互隔离。这是最基本的需求,两个不同的应用程序可能会依赖同一个第三方类库的不同版本,不能要求每个类库在一个服务器中......
  • Java 内存模型
    java虚拟机将内存区域划分为:方法栈本地方法栈堆程序计数器方法区其中,堆和方法区是线程共有的,其他都是每个线程私有的。程序计数器用于记录指令执行位置,以便线程正常切换方法栈和本地方法栈则是执行函数时存放的临时变量(变量的引用,即便是函数中生成的对象,也是存放在堆中......
  • windows系统为硬件保留的内存如何解决?
    这个问题在win7、win10、win11上都存在,但win10很明显更多,操作系统里边win10幺蛾子最多。为硬件保留的内存,是系统自己确定的,大多数时候无法人工调节,少数情况msconfig能够调节。正常的保留数量几十M几百M,要是大于500M一般用户都不大高兴了。如果保留的内存容量正好是一根内存......