一个JVM参数,服务超时率降了四分之三

一个,jvm,参数,服务,超时,四分之三 · 浏览次数 : 59

小编点评

**结论:** 通过优化Xms,改为和Xmx一致,使系统的超时率降了四分之三1。 **分析:** 1. 监控首先找了一台机器,看了监控上线后最明显的变化就是CPU使用率变高了。 2. 上线改动点上线只加了简单的判断条件,按理不应该导致CPU变高成这样2. 3. CPU使用率随时间变低又发现了一个奇怪的现象是,在没有上线的情况下,CPU使用率突然降低了,然后就一直保持着很低的状态CPU降低之后,超时率也有所降低,现在大概能理解超时是和CPU使用率有关的,可能存在CPU瓶颈。 4. 依赖的服务既然在没有上线的情况下,CPU使用率会降低,肯定有什么因素影响,猜测可能是依赖的服务,但依赖的服务太多,也没办法一个一个去看,哪个调用有问题。 5. CPU和上线的关系于是还是想在CPU使用率上找找问题,因为是上线导致的CPU使用率变高,所以看了其他上线时间的CPU使用率还是有点思路了,发现大部分上线之后CPU使用率是会变高,部分没有(后面知道,因为有的上线本身就是优化,所以CPU使用率也会变低) **其他重要信息:** * Xms配置过小,JVM启动时内存不足导致GC线程占用过多CPUCPU不足时,超时率增加,CPU充足时,超时率降低 * Xms和Xmx这两个参数使用Java的都比较了解Xmx: JVM的最大堆内存Xms: JVM的初始堆内存4.2 * 设置相等的Xms和Xmx值可以避免在生产环境由于heap内存扩大或缩小导致应用停顿,降低延迟,同时避免每次垃圾回收完成后JVM重新分配内存 * 容器也是可能造成浪费的,比如上面我把Xmx和Xms从16G改为14G,虽然性能提升了一点,但其实也是一种浪费

正文

先说结论:通过优化Xms,改为和Xmx一致,使系统的超时率降了四分之三

image.png

1. 背景

一个同事说他负责的服务在一次上线之后超时率增加了一倍

image.png

2. 分析

2.1 机器的监控

首先找了一台机器,看了监控
image.png

上线后最明显的变化就是CPU使用率变高了

2.2 上线改动点

上线只加了简单的判断条件,按理不应该导致CPU变高成这样

2.3 CPU使用率随时间变低

又发现了一个奇怪的现象是,在没有上线的情况下,CPU使用率突然降低了,然后就一直保持着很低的状态
image.png

CPU降低之后,超时率也有所降低,现在大概能理解超时是和CPU使用率有关的,可能存在CPU瓶颈

2.4 依赖的服务

既然在没有上线的情况下,CPU使用率会降低,肯定有什么因素影响,猜测可能是依赖的服务,但依赖的服务太多,也没办法一个一个去看,哪个调用有问题

2.5 CPU和上线的关系

于是还是想在CPU使用率上找找问题,因为是上线导致的CPU使用率变高,所以看了其他上线时间的CPU使用率

还是有点思路了,发现大部分上线之后CPU使用率是会变高,部分没有(后面知道,因为有的上线本身就是优化,所以CPU使用率也会变低)

2.6 CPU和内存的关系

之前一直在关心CPU,突然看见了内存的使用率,一下就明白的问题所在,从下面这张图可以看出,CPU使用率和内存使用率是成反比的

image.png

使用Java的都应该清楚,内存不够的时候,就会STW,然后去启动GC线程去GC,而且一般情况GC线程数和CPU核数是一致的,这个服务也是如此,此时CPU使用率必然是会变高的

上面3月6号CPU突然下降的原因也是因为内存使用变高了,这是在没有上线的情况下

image.png

2.7 内存和JVM参数

可以看到上面的图中,CPU使用率高的时候,内存占用只有20%左右,为什么空这这么多内存不用呢?看下JVM参数

-Xmx16g -Xms4g -Xss1024K -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=10 -XX:MetaspaceSize=512m -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:ParallelGCThreads=8 -XX:ConcGCThreads=8 -XX:G1HeapRegionSize=16m -XX:-OmitStackTraceInFastThrow

Xms配的是4G,也就是说JVM在启动时只会申请4G内存,当内存不足时,先会GC,当GC释放的内存还不够时,才会去申请更大的内存

这样的策略一般是为了节省内存,但目前主流的都是容器,节省下来的内存也不会给别的服务利用,所以我们这可以直接把Xms改为16G

改完之后立即得到了很好的效果,超时率降了四分之三,不过后续因为内存使用率变高,超过了阈值,所以又把Xmx和Xms调整为14G,这个问题可以参考我之前的文章一次Java服务内存过高的分析过程

3. 总结

  1. Xms配置过小,JVM启动时内存不足导致GC线程占用过多CPU
  2. CPU不足时,超时率增加,CPU充足时,超时率降低
  3. Xms配置和Xmx一样,超时率降低

4. Xms和Xmx

这两个参数使用Java的都比较了解

Xmx: JVM的最大堆内存
Xms: JVM的初始堆内存

4.2 不一致的坏处

  1. 堆内存不够时更频繁的触发GC
  2. 当GC完之后内存也不够时,向系统申请内存,会花费更多的时间

4.2 改为一致的好处

为了避免在生产环境由于heap内存扩大或缩小导致应用停顿,降低延迟,同时避免每次垃圾回收完成后JVM重新分配内存。所以,-Xmx和-Xms一般都是设置相等的

在生产环境中把Xms和Xmx设为相同值也是Oracle官方推荐

5. 感想

这个配置从机器上线跑了两年一直如此,大部分时间性能没被充分利用,现在有二十台机器都是以这样一种低性能模式跑了这么久,这绝对是一种浪费

在第三篇参考文章中,有个人的评论正好和我相反,他认为一开始将Xms和Xmx设置为一样,而实际没用那么多,其实也是一种浪费,不过这是18年前的文章,那时容器没有兴起,服务都在一个物理机上面共享内存,会是有这种问题的

在容器中,节省的内存别的服务也利用不了,所以Xms最后设置和Xmx一致,但是容器也是可能造成浪费的,比如上面我把Xmx和Xms从16G改为14G,从监控上来看耗时和超时率下降了一点,也就是把这个容器的内存往下调一点也是可以接受的,具体调到多少合适也不太确定

不过这种优化很没有必要,内存是很便宜的,而且适量冗余一些性能也可以理解

既然这么多好处,为什么Oracle不默认把Xms和Xmx设置为一致呢,我觉得可能是目前还是有大部分Java应用都不是容器环境,全局考虑,没有这样做,或许后续Java会判断是否是容器环境来自动设置Xms

参考

[1] JVM的Xms和Xmx参数设置为相同值有什么好处?

[2] Is there any advantage in setting Xms and Xmx to the same value?

[3] large difference between -Xms and -Xmx values in jvm

与一个JVM参数,服务超时率降了四分之三相似的内容:

一个JVM参数,服务超时率降了四分之三

先说结论:通过优化Xms,改为和Xmx一致,使系统的超时率降了四分之三 ![image.png](https://img2023.cnblogs.com/blog/2058002/202306/2058002-20230628185820689-1353266318.png) # 1. 背景 一个同

JVM启动参数脚本的再学习与研究

JVM启动参数脚本的再学习与研究 摘要 学无止境 前段时间一直再研究JVM参数调优. 但是最近也在想不应该仅研究如何调优. 因为不管怎么设置, 总有猪队友会把环境搞崩. 所以应该想办法在无人值守的情况下能够启动服务. systemd这种主流方式有时候不靠谱, 进程可能判断生死不准确. 所以还是想通过

[转帖]JVM参数之-XX:SurvivorRatio

https://www.cnblogs.com/hellxz/p/10841550.html 最近面试过程中遇到一些问JVM参数的,本着没用过去学习的办法看了些博客写得不准确,参考oracle的文档记录一下,争取每天记录一点知识点 -XX:SurvivorRatio=6 ,设置的是Eden区与每一个

[转帖]Native Memory Tracking 详解(1):基础介绍

https://www.modb.pro/db/516032 0.引言 我们经常会好奇,我启动了一个 JVM,他到底会占据多大的内存?他的内存都消耗在哪里?为什么 JVM 使用的内存比我设置的 -Xmx 大这么多?我的内存设置参数是否合理?为什么我的 JVM 内存一直缓慢增长?为什么我的 JVM 会

【转帖】16.JVM栈帧内部结构-局部变量表

目录 1.局部变量表(Local variables) 1.局部变量表(Local variables) 1.局部变量表也称为局部变量数组或本地变量表。 2.局部变量表定义为一个数字数组,主要用于存储方法参数和定义在方法体内的局部变量。(局部变量表的作用) 3.局部变量表示栈帧中的数据,栈帧被线程私

[转帖]jvm一般相关配置OutOfMemoryError关参数配置解释

一般运行java应用都会根据实际情况设置一些jvm相关运行参数 特别是有关内存和oom溢出等参数,方便后续问题定位和解决 如常用的以下配置 nohup java -Xms256m -Xmx24g -Xmn8g -verbose:gc -XX:+PrintGCDateStamps -XX:+Print

[转帖]查看docker中运行的JVM参数问题及解决方法

方法一、jcmd命令: 1、jps获取java的线程id 2、jcmd pidVM.flags获取 51152:-XX:CICompilerCount=3 -XX:InitialHeapSize=526385152 -XX:MaxHeapSize=1073741824 -XX:MaxNewSize=

JVM参数:带你认识-X和-XX参数

摘要:JVM参数分为三类:标准参数、非标准参数(-X参数)和高级选项(-XX参数)。本文主要为大家讲解-X参数和-XX参数。 本文分享自华为云社区《JVM运行参数之-X和-XX参数》,作者:共饮一杯无 。 JVM参数分为三类:标准参数、非标准参数(-X参数)和高级选项(-XX参数)。本文主要为大家讲

[转帖]JVM参数:-XX:ReservedCodeCacheSize

通过笨神的分享整理笔记: 这个参数主要设置codecache的大小,比如我们jit编译的代码都是放在codecache里的,所以codecache如果满了的话,那带来的问题就是无法再jit编译了,而且还会去优化。因此大家可能碰到这样的问题:cpu一直高,然后发现是编译线程一直高(系统运行到一定时期)

[转帖]JVM 参数

https://www.cnblogs.com/xiaojiesir/p/15636100.html 我们可以在启动 Java 命令时指定不同的 JVM 参数,让 JVM 调整自己的运行状态和行为,内存管理和垃圾回收的 GC 算法,添加和处理调试和诊断信息等等。 JVM参数选项 类型一:标准参数选项