[转帖]JVM 调优之 Reserved Code Cache Size

jvm,reserved,code,cache,size · 浏览次数 : 0

小编点评

**Root Cause Analysis for Kylin 4 Performance Degradation** **Problem:** * Query response time stability issues in Soft Affinity + Local Cache performance test under pressure. * Performance drops significantly over time, with a significant increase in RT during specific stages. * Restarting Spark can sometimes recover performance, but it also suffers from the same performance degradation issue. **Key Findings:** * GC analysis shows no major differences between baseline and stressed conditions. * Flame chart shows that the bottleneck lies in the executor code cache. * Code cache size performance metric plays a crucial role in determining the optimal code cache size. * Enabling the code cache can significantly improve performance, but it can also lead to JIT stopping if the cache is full. **Solutions:** 1. **Adjust Code Cache Size:** - Set `-XX:ReservedCodeCacheSize=2G` to allocate 2GB of code cache. - Adjust `-XX:+TieredCompilation` parameters to optimize compiler behavior. - Enable `-XX:UseCodeCacheFlushing` and set `-XX:Tier3CompileThreshold=2000` and `-XX:Tier4CompileThreshold=15000`. 2. **Monitor JVM Parameters:** - Keep an eye on `Code Cache Size` performance metric. - Use the Spark Metrics `Code Cache Size` gauge. **Additional Notes:** * Ensure that the `Code Cache Size` is not manually modified. * These parameters may have different values for different versions of Java and Spark. * The optimal code cache size may vary depending on the specific workload and system resources.

正文

https://www.modb.pro/db/251381

 

01

现象

 

社区小伙伴最近在为 Kylin 4 开发 Soft Affinity + Local Cache 的性能测试过程中,遇到了压测场景下查询响应时间不稳定问题, RT 随着时间变化较大,现象如下:

 

  1. 同样的 SQL (只是参数不同) 在压测时,刚开始的性能较好,运行一段时间后,性能就下降严重,一段时间后(不固定多长)又有可能恢复之前的水平;

  2. Spark 重启后,性能同样也能好转;

 

如下图所示:

图一:测试第一阶段和第二阶段

 

第一阶段,测试开始,查询响应时间比较平稳,在 1 秒左右;

 

第二阶段,16:06 以后查询的响应时间逐渐变大,慢慢增长到第一阶段的两倍,达到接近 2 秒;

 

图二:测试第三阶段

 

第三阶段,查询的响应时间慢慢恢复之前的水平。

 

 

02

寻找 Root Cause

 

相同的环境,一样的配置,每次运行都能复现这种现象,且性能相差巨大,不找出 Root Cause 似乎会失眠。于是开始了一波测试,观察 GC、收集火焰图、做性能下降前后的对比,发现均没有什么太大区别,且都正常。

 

根因排查

1.Spark Executor GC Log 分析

 

图三:Executor JVM 内存使用

 

图四:Executor JVM GC 耗时分布

 

根据 GC log 分析,大部分 GC 在 20ms 内,比较正常,Peak Memory Size 也毫无压力。

 

2.Spark Executor 火焰图

 

图五:Executor 火焰图

 

从火焰图上看,唯一区别在于小红框部分的比例前后不同,但这部分是 Spark Code Generate 的代码,相同的 SQL ,代码逻辑是一样,大红框整体的占比也是差不多的(后来回想,这是一个异常点,只是当时无法想到是跟 JIT 有关)。

 

3.Parquet 读取

 

图六:Executor 读取文件相关部分火焰图

 

从火焰图上可以看到,紫色部分是读取 Parquet 数据部分,占比和正常水平时的一样。

 

关键线索

一切看起来都是那么的正常,但为什么却有两倍的 RT 呢?毫无头绪下,只能再回归各种指标数据,日志文件了。

 

在看 Executor stderr log 时,无意间看到了这个 Warning,且各个 Executor 上都有:

 

图七:JVM Warning Message on Executor stderr

 

因此开启 Code Cache Size 性能指标采集 (该性能指标似乎自己平时比较少关注),再压测一轮,发现了端倪:Code Cache 影响了查询性能。

 

查看 JMeter Report 中随时间变化的 RT 曲线,并且结合 Spark Metrics 的 Code Cache Size 曲线,发现 RT 翻倍的时间点与各个 Executor Code Cache Size 满的时间点吻合:

 

图八:Kylin 4 Response Time 曲线图

 

图九:Spark Executor Code Cache Size 曲线图

 

在 RT 高峰时,所有 Executor 的 Code Cache Size 均达到最大值,后续有些 Executor 的 Code Cache Size 因为回收机制下降下来,此时的 RT 也开始略有好转,当所有 Executor 的 Code Cache 都未达到最大值时,RT 恢复正常。

 

Root Cause

经过上面的分析,接着验证下是否分析正确,因此把 JVM 参数 -XX:ReservedCodeCacheSize=256M 调整为 2G ( 目前该参数最大可配置 2G ),再次压测一轮,整体 RT 就稳定了许多:

图十:调整后 Kylin 4 Response Time 曲线图

 

且观察 Code Cache Size 性能指标,发现最大值可达到 400M:

图十一:调整后 Spark Executor Code Cache Size 曲线图

 

至此,Root Cause 找到了,因为 Code Cache Size 满了,导致了 JIT 停止,而 JIT 是 JVM 提升性能的一把利器,停止了工作,随之带来的性能下降显而易见,影响巨大。

 

 

03

小结

 

1. Code Cache Size 的性能指标,对 JIT 功能至关重要,必须监控起来,然后根据实际使用情况,进行适当调整;

 

2. JVM 中 Code Cache Size 及 JIT 等相关参数:

  • -XX:+TieredCompilation:开启分层编译( C1 and C2 ),JDK 8 之后默认开启;

     

  • -XX:+UseCodeCacheFlushing:在JIT被关闭之前,也就是 CodeCache Size 满之前,会做一次清理,删除一些 Code Cache 的代码,如果清理后还是没有空间,那么 JIT 依然会关闭,JDK 8 默认开启;

     

  • -XX:ReservedCodeCacheSize=2G:Code Cache Size,最大可配置 2G;

     

  • -XX:NmethodSweepActivity=10:默认值 10,计算清理 compiled method 的阈值,具体可以看对应的代码:http://hg.openjdk.java.net/jdk8u/jdk8u/hotspot/file/f22b5be95347/src/share/vm/runtime/sweeper.cpp#l588 ;值越大,在清理时会有越多的 compiled method 被清理,意味着回收会越快;

     

  • -XX:Tier3CompileThreshold=2000 and -XX:Tier3InvocationThreshold=200:开启分层编译后,C1 层编译和调用的阈值,值越小,越容易被 JIT 编译;

     

  • -XX:Tier4CompileThreshold=15000 and -XX:Tier4InvocationThreshold=5000:开启分层编译后,C2 层编译和调用的阈值,值越小,越容易被 JIT 编译;

 

* 以上四个参数,官方建议不要自行修改

 

04

参考资料

1. 基本功 | Java 即时编译器原理解析及实践

2.https://stackoverflow.com/questions/38173592/oracle-jvm-8-when-codecache-flushing-is-enabled-how-much-is-flushed

与[转帖]JVM 调优之 Reserved Code Cache Size相似的内容:

[转帖]JVM 调优之 Reserved Code Cache Size

https://www.modb.pro/db/251381 01 现象 社区小伙伴最近在为 Kylin 4 开发 Soft Affinity + Local Cache 的性能测试过程中,遇到了压测场景下查询响应时间不稳定问题, RT 随着时间变化较大,现象如下: 同样的 SQL (只是参数不同)

[转帖]高并发场景下JVM调优实践之路

https://www.jianshu.com/p/f5f5f99e2417 一、背景 2021年2月,收到反馈,视频APP某核心接口高峰期响应慢,影响用户体验。 通过监控发现,接口响应慢主要是P99耗时高引起的,怀疑与该服务的GC有关,该服务典型的一个实例GC表现如下图: image image

[转帖]JVM系列之:GC调优基础以及初识jstat命令

本文为《深入学习 JVM 系列》第二十二篇文章 影响垃圾收集性能有三个主要的属性,垃圾收集调优又有三个基本原则,以及垃圾收集调优时需要采集的信息。如果想要对垃圾收集进行调优,则需要根据实际场景对不同属性做出取舍,理解调优的原则以及收集什么信息。 性能属性 吞吐量 吞吐量是评价垃圾收集器能力的重要指标

[转帖]小知识点 之 JVM -XX:MaxGCPauseMillis 与 -XX:GCTimeRatio

https://www.cnblogs.com/hellxz/p/14056403.html 写在前边 JVM调优更多是针对不同应用类型及目标进行的调整,往往有很大的实验成份,通过实验来针对当前应用设置相对合适的参数,提高应用程序的性能与稳定性 最近在复习JVM,Parallel Scavenage

[转帖]JVM调优常用命令(jstat、jmap、jstack)

原文:https://www.cnblogs.com/ityouknow/p/5714703.html 一、jstat jstat(JVM statistics Monitoring)是用于监视虚拟机运行时状态信息的命令,它可以显示出虚拟机进程中的类装载、内存、垃圾收集、JIT编译等运行数据。 命令

[转帖]JVM调优汇总(JDK1.8)

JVM调优汇总 1、根据实际情况选择合适垃圾收集器 堆内存4G一下可以用parallel,4-8G可以用ParNew + CMS,8G以上可以用G1,几百级以上用ZGC。 2、jvm参数的初始值和最大值设置一样,避免扩容时消耗性能。 ‐Xms3072M ‐Xmx3072M ‐XX:Metaspace

[转帖]JVM性能调优监控工具

原文 https://www.cnblogs.com/haiyang1985/p/7654654.html 摘要: JDK自己提供了不少方便的JVM性能调优监控工具,除了集成式的VisualVM和jConsole外,还有jps、jstack、jmap、jhat、jstat、hprof等小巧的工具,本

[转帖]JVM常用命令和性能调优建议 [Could not create the Java virtual machine]

https://blog.51cto.com/u_6215974/4938440 一、查看jvm常用命令 jinfo:可以输出并修改运行时的java 进程的opts。 jps:与unix上的ps类似,用来显示本地的java进程,可以查看本地运行着几个java程序,并显示他们的进程号。 jstat:一

[转帖]第七篇:双管齐下,JVM内部优化与JVM性能调优

文章目录 一、前言二、编译时优化2.1 Javac编译器2.2 Java语法糖2.2.1 泛型和泛型擦除2.2.2 自动装箱、自动拆箱、遍历循环2.2.3 条件编译 三、运行时优化(核心:JIT编译器/即时编译器)3.1 HotSpot虚拟机内的JIT编译器3.1.1 编译器和解释器并存的架构3.1

[转帖]性能优化 YYDS - Brendan Gregg 与 Intel.com 的故事

https://www.modb.pro/db/421309 译者序 金庸笔下的《鹿鼎记》有: !! 平生不识陈近南,便称英雄也枉然 现代的认真搞技术的后端程序员,应该也有一句: !! 平生不识 Brendan Gregg,便呆 BAT 也 SoSo 从 2016 年开始,做一个 JVM 调优开始,