JIT逆优化引发的Java服务瞬时抖动 问题排查解决方案

目录

一、背景

二、前期排查(失败)

三、使用神器JFR

四、学习JIT&思考解决方案

五、最终的解决方案

五、总结

一、背景

我们有一个QPS较高、机器数较多的Java服务;该服务的TP9999一般为几十ms,但偶尔会突然飙升至数秒,并会在几秒内自动恢复(抖动期间伴随着CPU占用100%、线程池大量扩容)。抖动大都集中在新代码上线后的前几天,会随着时间拉长逐渐减少。

二、前期排查(失败)

前期未排查到问题根因,也不知道如何去定位根因;只好从现象出发(CPU占用100% 和 线程池大量扩容),尝试通过解决表面现象,从而避免服务抖动。具体做了以下工作进行测试验证:

工作项预期结果
固定线程池线程数避免因线程创建销毁、线程上下文切换产生的CPU开销抖动时的TP峰值降低,但抖动仍存在
监控线程CPU占用的shell脚本捕获异常时刻到CPU占用高的线程捕获到的线程比较多,有业务代码线程、C2编译器线程、GC线程...
JIT调优(提高编译阈值、减少C2线程数...)降低CPU占用效果不明显
试用JDK21的虚拟线程避免因线程创建销毁、线程上下文切换产生的CPU开销使用虚拟线程后,抖动时的TP峰值降低,但抖动仍存在
试用JDK21的结构化并发避免部分业务线程查存储失败后,其他线程还在运行、持续占用CPU结构化并发也是基于虚拟线程的,效果和虚拟线程类似
试用分代ZGC降低GC线程的CPU占用无效

这时候我们发现针对表面的现象可以做的猜想实在是太多了,对应的实验也太多了,很多时候也很难通过实验去完全地证伪这些猜想。

基于“抖动大都集中在新代码上线后的前几天”的现象,服务冷启动和JIT编译确实有很大的嫌疑,但是JIT编译真的会持续这么多天吗?我们并不能理解,开启了JIT编译日志打印也没看出什么。并且JIT参数调优我们也试了,效果也并不明显。

排查陷入了停滞...

三、使用神器JFR

1、JFR的简介与作用

JFR全程是Java Flight Recorder,即Java飞行记录器。借助JFR我们可以把Java服务的各种事件记录下来,如:各种JIT事件的发生时刻、原因等细节;新开线程的时间;各个时间点各线程对CPU的占用情况...这样就可以把服务异常时刻的各种指标记录下来,大大提升服务的可观测性。

详细了解推荐这位大佬的系列博客:Java 监控 JFR

2、JFR常用命令

# JVM参数开启JFR
-XX:StartFlightRecording=filename=/logs/flight.jfr,maxsize=10g
-XX:FlightRecorderOptions=repository=/logs/tmp #指定临时记录的目录
# 检查正在运行的JFR
jcmd JFR.check
# JFR不会自动导出记录,需要通过命令转储
# 转储所有的记录
jcmd <pid> JFR.dump filename=/logs/flight.jfr
# 转储最后n小时的记录
jcmd <pid> JFR.dump begin=-1h
jcmd <pid> JFR.dump maxage=1h
# 转储指定日期
jcmd <pid> JFR.dump begin=2024-01-01T13:00:00 end=2024-01-01T14:00:00 filename=/logs/flight.jfr

3、使用JFR定位问题根因

有了工具的加持,后面的问题排查就顺利了很多。我们很容易就发现了服务的抖动总是伴随着JIT的逆优化、再编译事件,并且逆优化的原因几乎都是C2激进的分支预测发生了失败,逆优化的代码集中在依赖的json库上。

四、学习JIT&思考解决方案

相关资料

JIT分层编译阈值策略

基本功 | Java即时编译器原理解析及实践 - 美团技术团队

(下图来自上文)

思考

  • 由上述资料我们可以得知,JIT的level 4编译发生逆优化后,代码将发生解释运行
  • 此时我们几乎可以猜测抖动就是来自于JIT逆优化后的解释运行(解释运行性能极差),所以解决方案的核心在于避免逆优化
  • level 1编译不会发生逆优化,可以将分层编译固定在level 1,但是性能会比level 4差30%(实测性能发生了不小的下降,方案不够完美,但TP抖动确实消失了)
  • 因为逆优化集中在json库,尝试更换其他json库(失败,没有效果)
  • 修改分层编译的阈值,避免大量方法被level 2、3、4编译(失败,产生了连锁反应,抖动加剧)
  • 再次陷入了僵局...

五、最终的解决方案

山重水复疑无路,柳暗花明又一村。灵光乍现+好运加成,终于被我找到了两个很有效的方案!

1、使用graal编译器

-XX:+UnlockExperimentalVMOptions -XX:+UseJVMCICompile

压测的效果不错,压测了10小时抖动只发生的1~2次,差不多是原来的1/10。

猜测可能是graal对分支预测相关的逻辑有优化,避免了频繁的逆优化及代码的解释运行。

2、修改OpenJDK源码禁用C2的分支预测

  • openjdk编译流程:Building the JDK

  • openjdk源码下载:GitHub - openjdk/jdk: JDK main-line development https://openjdk.org/projects/jdk

  • openjdk源码修改,注释分支预测逻辑,直接返回PROB_FAIR(Fair probability 50/50,即各有一半的机会):

    //-----------------------------branch_prediction-------------------------------
    float Parse::branch_prediction(float& cnt,BoolTest::mask btest,int target_bci,Node* test) {return PROB_FAIR;// float prob = dynamic_branch_prediction(cnt, btest, test);// // If prob is unknown, switch to static prediction// if (prob != PROB_UNKNOWN)  return prob;// prob = PROB_FAIR;                   // Set default value// if (btest == BoolTest::eq)          // Exactly equal test?//   prob = PROB_STATIC_INFREQUENT;    // Assume its relatively infrequent// else if (btest == BoolTest::ne)//   prob = PROB_STATIC_FREQUENT;      // Assume its relatively frequent// // If this is a conditional test guarding a backwards branch,// // assume its a loop-back edge.  Make it a likely taken branch.// if (target_bci < bci()) {//   if (is_osr_parse()) {    // Could be a hot OSR'd loop; force deopt//     // Since it's an OSR, we probably have profile data, but since//     // branch_prediction returned PROB_UNKNOWN, the counts are too small.//     // Let's make a special check here for completely zero counts.//     ciMethodData* methodData = method()->method_data();//     if (!methodData->is_empty()) {//       ciProfileData* data = methodData->bci_to_data(bci());//       // Only stop for truly zero counts, which mean an unknown part//       // of the OSR-ed method, and we want to deopt to gather more stats.//       // If you have ANY counts, then this loop is simply 'cold' relative//       // to the OSR loop.//       if (data == nullptr ||//           (data->as_BranchData()->taken() +  data->as_BranchData()->not_taken() == 0)) {//         // This is the only way to return PROB_UNKNOWN://         return PROB_UNKNOWN;//       }//     }//   }//   prob = PROB_STATIC_FREQUENT;     // Likely to take backwards branch// }// assert(prob != PROB_UNKNOWN, "must have some guess at this point");// return prob;
    }

    压测的效果极好,抖动几乎完全消失,并且接口的AVG、TP9999指标并未发生明显下降。

六、总结

  1. 可观测性对计算机系统极其重要,良好的可观测性可以大大提高问题排查、性能优化的效率
  2. 工欲善其事,必先利其器。掌握各种性能分析、问题排查、效率提升工具的使用是很有必要的
  3. 先分析清楚问题的根因才可以解决问题,没找到正确方向的努力只会是隔靴搔痒
  4. 阅读第一手的文档资料(当然大都是英文的),才能得到最准确的信息(这里推荐一个浏览器插件“沉浸式翻译”,可以实现中文与原文的对照阅读)
  5. 对于不同的技术积累,解决问题的维度也是不一样的。熟悉底层技术/源码,能做出惊艳的效果。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/670623.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

OnlyOffice:释放无限创意,打造高效协作新体验

Onlyoffice &#x1f496;前言一、&#x1f4ab;开发者版本介绍二、&#x1f4ab;开发者版本特点三、&#x1f4ab;最新版重磅来袭&#xff0c;8.0版本介绍1.显示协作者头像2.插件 UI 界面更新 四、✨Windows部署ONLYOFFICE1.安装Erlang2.安装RabbitMQ3.安装Redis4.安装Postgre…

CSS:两列布局

两列布局是指一列宽度固定&#xff0c;另一列自适应。效果如下&#xff1a; HTML: <div class"container clearfix"><div class"left"></div><div class"right"></div> </div>公共 CSS&#xff1a; .con…

Elasticsearch:BM25 及 使用 Elasticsearch 和 LangChain 的自查询检索器

本工作簿演示了 Elasticsearch 的自查询检索器将非结构化查询转换为结构化查询的示例&#xff0c;我们将其用于 BM25 示例。 在这个例子中&#xff1a; 我们将摄取 LangChain 之外的电影样本数据集自定义 ElasticsearchStore 中的检索策略以仅使用 BM25使用自查询检索将问题转…

【Vue】指令之列表循环、表单元素绑定

Vue指令[3] 列表循环、表单元素绑定v-for指令v-model指令 列表循环、表单元素绑定 v-for指令 作用&#xff1a;根据数据生成列表结构 数组经常和v-for结合使用数组长度的更新会同步到页面上面&#xff0c;是响应式的 语法&#xff1a;(item,index) in 数据&#xff0c;其中…

2023 OpenHarmony 年度运营报告

汇聚 70 家企业 6700名贡献者力量&#xff0c; OpenHarmony 已成为下一代智能终端操作系统根社区&#xff1b; 我们在成长,OpenHarmony 项目群成员单位增至 35 家&#xff1b; 2023 年持续迭代更新 6 个版本及 OpenHarmony4.0 重点特性简介……

Stable Diffusion 模型下载:RealCartoon3D - V14

文章目录 模型介绍生成案例案例一案例二案例三案例四案例五案例六案例七案例八案例九案例十下载地址模型介绍 RealCartoon3D 是一个动漫卡通混合现实风格的模型,具有真实卡通的 3D 效果,当前更新到 V14 版本。 RealCartoon3D 是我上传的第一个模型。我仍在学习这些东西,但…

计算机毕业设计 基于SpringBoot的线上教育培训办公系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

C语言数组练习以及场景练习题

写了那么久的知识点梳理&#xff0c;今天来写点自己觉得不错的练习题来分享&#xff0c;顺便来巩固自己的知识点&#xff0c;和加强题型的解决方法的记忆。今天给大家带来的有数组的找数字题目&#xff0c;以及场景找凶手的题目&#xff0c;下面让我们来看看今天的第一道题目。…

进程间通信:有名管道

如果读端关闭&#xff0c;写端继续向管道内写数据将会导致管道破裂&#xff0c;内核将会发送信号SIGPIPE到进程中&#xff0c;该信号的默认处理方式为结束进程&#xff1b; 如果写端关闭&#xff0c;读端继续从管道中读取数据将会读不到任何数据&#xff1b; 管道文件的大小固定…

Linux基础-磁盘

1.磁盘分区 1.分区有固定大小 2.直接写在这块盘的磁盘分区表中&#xff08;DPT&#xff09;&#xff0c;和上面装什么操作系统没有任何关系 2.每一个磁盘分区都要先有一个磁盘分区类型 GPT&#xff08;首选&#xff09; MBR 3.磁盘专业术语叫做块设备&#xff08;Block Dev…

洗地机哪个质量好?2024洗地机选购推荐

地面清洁作为大扫除的重要部分&#xff0c;看似简单&#xff0c;却也让很多人头疼。地板上的奶渍、厨房的油渍酱渍……遇到顽固污渍&#xff0c;普通的清洁工具很难去除&#xff0c;即便用湿抹布勉强去除&#xff0c;也会残留不少水渍&#xff0c;只能反复擦拭&#xff0c;费时…

行业科普应用分享 | 用于安全和安保的仪器仪表

【前言】 物联网带来了对安全和安保的新要求。利用物联网&#xff0c;运营商可以从复杂和分布式的装置中获益。此外&#xff0c;自主系统在现代工业的运作中正变得越来越重要。 从制造业到农业&#xff0c;这些远程操作需要仪器提供持续监测&#xff0c;以提供安全和保障。这…

MySQL学习记录——사 表结构的操作

文章目录 1、创建表2、查看表结构3、改变表结构4、删除表5、总结 1、创建表 CREATE TABLE table_name ( field1 datatype, field2 datatype, field3 datatype ) character set 字符集 collate 校验规则 engine 存储引擎; 例子 create table users ( id int, name varchar(20) c…

计算机设计大赛 深度学习+opencv+python实现昆虫识别 -图像识别 昆虫识别

文章目录 0 前言1 课题背景2 具体实现3 数据收集和处理3 卷积神经网络2.1卷积层2.2 池化层2.3 激活函数&#xff1a;2.4 全连接层2.5 使用tensorflow中keras模块实现卷积神经网络 4 MobileNetV2网络5 损失函数softmax 交叉熵5.1 softmax函数5.2 交叉熵损失函数 6 优化器SGD7 学…

第5节、S曲线加减速转动【51单片机+L298N步进电机系列教程】

↑↑↑点击上方【目录】&#xff0c;查看本系列全部文章 摘要&#xff1a;本节介绍步进电机S曲线相关内容&#xff0c;总共分四个小节讨论步进电机S曲线相关内容 5-1、S曲线加减速简介   根据上节内容&#xff0c;步进电机每一段的速度可以任意设置&#xff0c;但是每一段的…

Backtrader 文档学习-Indicators- TA-Lib

Backtrader 文档学习-Indicators- TA-Lib 1.概述 即使BT提供的内置指标数量已经很多&#xff0c;开发指标主要是定义输入、输出并以自然方式编写公式&#xff0c;还是希望使用TA-LIB。原因: 指标X在指标库中&#xff0c;而不在BT中TA-LIB众所周知的&#xff0c;人们信任口碑…

XUbuntu22.04之两款实用画笔工具(二百一十)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

centos 7.6 安装 openldap 2.5.17

centos 7.6 安装ldap 1、下载ldap2、安装ldap2.1、官方参考文档2.2、安装前准备2.2.1、安装gcc2.2.2、安装Cyrus SASL 2.1.272.2.3、安装OpenSSL 1.1.12.2.3.1、下载openssl 3.02.2.3.2、安装依赖包2.2.3.3、编译安装openssl 3.0 2.2.3、安装libevent 2.1.82.2.4、安装libargon…

Flink cdc3.0动态变更表结构——源码解析

文章目录 前言源码解析1. 接收schema变更事件2. 发起schema变更请求3. schema变更请求具体处理4. 广播刷新事件并阻塞5. 处理FlushEvent6. 修改sink端schema 结尾 前言 上一篇Flink cdc3.0同步实例 介绍了最新的一些功能和问题&#xff0c;本篇来看下新功能之一的动态变更表结…

新零售的升维体验,摸索华为云GaussDB如何实现数据赋能

新零售商业模式 商业模式通常是由客户价值、企业资源和能力、盈利方式三个方面构成。其最主要的用途是为实现客户价值最大化。 商业模式通过把能使企业运行的内外各要素整合起来&#xff0c;从而形成一个完整的、高效率的、具有独特核心竞争力的运行系统&#xff0c;并通过最…