Troubleshooting系列-应用JVM启动参数调优实践

最近重新梳理了JVM参数以及垃圾收集器相关知识,准备拿现网一些应用实践优化下

1. 问题现象

选取去年新建立一个应用服务,后台架构基于spring boot+ mybatics + druid + dubbo + rocktemq进行搭建。上线后,发现该应用每天fullgc次数10+。业务高峰期可能半个小时或者1个小时一次,每次fgc时间大概在500ms。

选取一个具体的major gc详看,major gc前

major gc后

2. 问题分析

2.1 JVM参数分析

这个应用JVM启动参数如下

shell 复制代码
#!/bin/bash

# 设置Java堆栈大小
JAVA_OPTS="$JAVA_OPTS -Xmn1024m -Xms1024m -Xmx4096m -XX:MetaspaceSize=64m -XX:MaxMetaspaceSize=256m"
JAVA_OPTS="$JAVA_OPTS -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=8 -XX:-UseAdaptiveSizePolicy"
# 垃圾收集器设置
JAVA_OPTS="$JAVA_OPTS -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:CMSInitiatingOccupancyFraction=60"
JAVA_OPTS="$JAVA_OPTS -XX:+CMSClassUnloadingEnabled"
...

结合上面一次major jc截图分析,发现堆在达到2.84G就开始major gc,gc完之后1.43g

从中发现两个问题:

  • 堆最大4g,2.84g后开始major gc,大概有1g多内存纯属浪费掉了
  • gc完之后还剩下1.43g,这个应用除了少部分缓存需要本地常驻外,大部分都是朝生夕死对象

结合启动参数,2.86g原因是-XX:CMSInitiatingOccupancyFraction=60,老年代占用达到60就开始major gc,以及-XX:SurvivorRatio=8年轻代晋升老年代次数偏低,查看yonggc概率,比较正常

综上所述,JVM参数调优如下

  1. -Xmn 1024m -> 2g (调大年轻代)
  2. -XX:CMSInitiatingOccupancyFraction=60 -> 85
  3. MaxTenuringThreshold=8->15 主要调整年轻代和老年代比例以及晋升难度增大,增加老年代堆内存使用率

2.2 堆内对象分析

major gc后堆内内存还是比较大,从现网取heap dump后,分析堆内内存分布情况

shell 复制代码
//123 通过jps获取应用进程替换 
jmap -dump:format=b,file=123.bin 123 
jstack -1 123>123jstack.txt 
jmap dump:live,format=b,file=123.bin2 123

获取堆后,查看top对象

发现有三类对象比较瞩目

  1. xxx.cacheItem 576m 这个是本地采用caffine做的本地缓存,缓存的有效期在1min,
java 复制代码
expireAfterWrite(1, TimeUnit.MINUTES)

当前caffine设置的最大缓存key是65535,实际使用时没这么多,一次major gc后大部分都清理掉了,可以把缓存最大key调低 65535->10240

  1. com.mysql.cl.jdbc.Connectianimpl 129.5m
    查看引用,最终是在 com.mysql.cj.jdbc.AbandonedConnectionCleanup这个druid的清理jdbc连接的thread中

不过这个问题网上有人解释过MySQL Connector内存增长问题排查 解决方案有两个

方案一不知是否有其他影响,当前采用方案2,减少连接数

目前采用的是druid,配置了单机最大连接数200,最少连接数5 mysql最大连接数2w左右,目前使用的是分库,但是每个数据库都合设在一起,导致一个应用和数据库的连接数是n*8*200,n当前大于20,导致最大连接数超过数据库本身配置,需要调低

最先连接数5也不对,高峰期,每个数据库实例一分钟4000个连接,最小的5连接数也不够,可能会导致连接数不断地创建和释放

调整druid的数据库连接池大小 maxActive=200 ->80 minIdle=5 ->15

  1. sun.security.ssI.SSLSessionContextImpl 132m 这个暂时没找到原因,先不管

3. 分析结果

根据上述结果,准备在下次升级时调整上述参数,调整运行情况等上线后更新结果

3.1 JVM调优策略

主要从堆大小 垃圾回收停顿时间 垃圾回收频率三个方向来调节

本次主要优化堆布局,并且增加垃圾回收频率

4. 参考

github.com/ben-manes/c...
本地缓存Caffeine的缓存过期淘汰策略
Java 8 内存管理原理解析及内存故障排查实践

相关推荐
高频因子挖掘机1 小时前
回测收益为什么可能不真实?从时间戳、数据可用性到未来函数检查
后端·github·api
Joy T5 小时前
Agent 确定性上下文设计:从 Prompt 参数注入到能力分层
java·开发语言·微服务·架构·prompt·agent context
m0_587383008 小时前
广州 24 小时自助健身房解决方案技术实现与实战指南
java·spring·小程序·架构·需求分析
·云扬·8 小时前
Prompt 工程与安全:从 System 设计到注入防御
java·人工智能·安全·ai·prompt
代码不停9 小时前
自动化测试(java)
java·开发语言·selenium·自动化
行百里er9 小时前
Redis 完结篇——Redis 热点问题在 Spring Boot 项目中实战
redis·后端
高频因子挖掘机10 小时前
只取最近 60 个交易日,却每次拉全历史:量化脚本变慢的原因与改法
后端·github·api
鬼手点金11 小时前
opencode-rules 插件
java·开发语言·前端·人工智能·chrome·git·github
孟健11 小时前
从5000亿Token到83%字节匹配:AI逆向工程与重构的工程闭环实践
后端·架构·ai编程
paopaokaka_luck12 小时前
滑雪场管理系统(AI智能助手流式对话,ECharts 运营数据分析、教练、雪具与场地一体化预约,钱包支付退款、订单核销与服务评价)
java·人工智能·spring boot·网络协议·数据分析·echarts