调整jvm参数_线上服务JVM性能调优经验分享

9da26092a376bf8d87e9ce8c17b0476d.png

最近我们新上了一个预测模型的解决方案,其中有一步,不同于以往用复杂逻辑对稀疏处理特征的预处理方式,而是通过创建数百个Tensor来做预处理,一个tensor创建时间大概是0.2ms,用for循环串行执行创建数百个tensor,单次请求耗时可达到50ms,加上后面的预测,1并发下耗时就达到了65ms,压测状况如下:

f879aa3105e735e1e1e0f1c6d6685415.png

也就是并发到了6或者7,已经开始出现超时了,这和我们的目标相去甚远。那么很简单的,我们想到了用parallelStream来完成循环处理。

e8d1458dbcdabf7ac69b2ae61113f9a9.png

果然,单次预处理逻辑耗时下降到了15ms以内,于是我们满心欢喜的把他发上去压测,结果是:

98a9e7116c6e8200f3aea8c1ac1fde54.png

耗时并没有好,而且突增的很明显,在并发到了3的时候就已经耗时80ms了。其实这也很好解释,并行流parallelStream会最大地利用并行度,消耗大量的线程和CPU资源,而作为运算密集型的模型服务,CPU被前置逻辑消耗了必然会影响整体性能。

0f44790e554bd65aaf1465f5beb73b05.png
他居然想用我11个核!

当我打开应用监控,果然是这样的:

5edd39f93acb87f9d18e1eb83a5ba7c2.png
CPU已经炸了

我第一反应就是要降低并行度,查阅了资料和源码,并行流底层使用的是ForkJoinPool作为线程池,于是我尝试了用System.property("java.util.concurrent.ForkJoinPool.common.parallelism",4)和在JVM参数里-Djava.util.concurrent.ForkJoinPool.common.parallelism=4(这个数据经过后续多次测试调成了5)设置,为了避免spring加载的时候把一些系统参数覆盖以及想让spring入口美观点,就干脆只保留JVM里的配置了,压测结果:

8e5ccfd1ea6d31d1c6c852aa8f6565c1.png

发现CPU负载是下来了,也没有突增,但是整体和不开parallelStream区别不大,那真的没有办法了吗?


在我增加JVM参数的时候,发现了几个以前的配置:

-XX:ReservedCodeCacheSize=512m -XX:MaxMetaspaceSize=1g -XX:NativeMemoryTracking=detail

瞬间对这几个参数产生了兴趣

ReservedCodeCacheSize:

用于设置Code Cache大小,JIT编译的代码都放在Code Cache中,若Code Cache空间不足则JIT无法继续编译,并且会去优化,比如编译执行改为解释执行,由此,性能会降低

我是第一次知道原来java也有可能进行解释执行啊,这不成了边吃边拉的python了吗(无恶意 如果空间不足性能必然会大大降低,作为一台12核48G的服务器,不能忍,先改成1G。当然了,这个参数的改动并不会对本次压测产生影响,因为JVM日志里并没有报 ->

CodeCache已满,编译器已被禁用

MaxMetaspaceSize:

最大元空间占用内存大小,这个就是标准的JAVA基础知识了,不赘述(我说的也不好),那么他有必要配1g吗?

ba8c41cb218d1fde368432b01094cfe4.png
阿里提供了元空间的监控

看来我并没有那么多的类和类加载器,何必占用JVM的空间?调小调小。

可是调整元空间占用大小也仅仅是释放一些创建线程的压力(可用内存越少,可创建的线程越少),并不能明显解决已减少了并行度的服务的耗时呀。

接下来才是重头戏:

NativeMemoryTracking:

这个参数其实是之前为了排查堆外内存泄露问题时加上的,一直没有关(至于堆外内存泄露如何解决又是另一个故事了),那么这个参数会对JVM带来哪些影响呢?

Native Memory Tracking (NMT) 是Hotspot VM用来分析VM内部内存使用情况的一个功能。我们可以利用jcmd(jdk自带)这个工具来访问NMT的数据。NMT必须先通过VM启动参数中打开,不过要注意的是,打开NMT会带来5%-10%的性能损耗。

配置参数:

-XX:NativeMemoryTracking=[off | summary | detail]

# off: 默认关闭# summary: 只统计各个分类的内存使用情况.# detail: Collect memory usage by individual call sites.

通过jcmd查看NMT报告以及查看对比情况。

jcmd <pid> VM.native_memory [summary | detail | baseline | summary.diff | detail.diff | shutdown] [scale= KB | MB | GB]

# summary: 分类内存使用情况 # detail: 详细内存使用情况,除了summary信息之外还包含了虚拟内存使用情况 # baseline: 创建内存使用快照,方便和后面做对比 # summary.diff: 和上一次baseline的summary对比 # detail.diff: 和上一次baseline的detail对比 # shutdown: 关闭NMT

显然,之前查找问题加上的这个参数影响了我们服务的整体性能,而且可能不少,压测的时候完全可以把这个参数设置为off状态

那么。。。见证奇迹的时候到了

d06c23f24e41d1fa0694550b382738b5.png

我们成功的把并发压上了10,并且RT完全可接受,整体的吞吐率和QPS均符合线上切小流量的标准!!!

通过对JVM的调整我们成功实现了性能优化1.5倍的目标,而且在这些参数上线之后,可能对整个系统所有接口都有正向的影响,待后续更新。


---> 我来更新了

fd8cb94b217ad706ae0db0273d678cbb.png
这是原来的耗时

9629044ef685f272b7b9644cbab9fe89.png
这是今天的耗时

调参大法好~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值