Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >线上服务发布抖动,该怎么解决呢

线上服务发布抖动,该怎么解决呢

作者头像
卷福同学
发布于 2023-04-28 03:59:51
发布于 2023-04-28 03:59:51
4480
举报
文章被收录于专栏:奶奶看了都会奶奶看了都会

之前的文章分别讲了优雅上线 和 优雅下线,实际工作中做了优雅上下线后,服务发布后还是会有短暂的“抖动”,接口的响应时间急剧升高后又恢复正常,就和下面的监控图一样,图片来源于 得物 的InfoQ技术文档服务发布时网络“抖动”

背景

小卷现在负责的系统已经达到20万QPS了,每天即使是在半夜,QPS依然过万。每次系统升级发布时,抖动比较频繁,上游应用方都跑过来质问,怎么服务又超时了啊,还能不能用了。。。(巴拉巴拉),小卷只能陪着笑脸的一番解释。后来小卷加上了优雅上下线,想着这下发布应该没问题了吧。哪知再次发布,超时问题依然存在。。。小卷决定好好分析一下发布抖动问题的根因是啥

1.抖动问题分析

服务抖动问题需要根据具体场景分析,这里列一下可能的原因:

  • • redis、DB连接初始化耗时长,引起启动后的接口RT升高
  • • JIT即时编译耗时长,造成CPU利用率高,引起接口RT升高

对于高并发的应用来说,这里JIT即时编译是通用的原因。

JIT是什么?

JIT(just-in-time)即时编译,是一种执行计算机代码的方法,这种方法涉及在程序执行过程中(在执行期)而不是在执行之前进行。关于JIT的历史,摘抄一段维基百科上的内容

最早发布的JIT编译器是 约翰·麦卡锡在1960年对LISP的研究。在他的重要论文《符号表达式的递归函数及其在机器上的计算》(Recursive functions of symbolic expressions and their computation by machine, Part I)提到了在运行时被转换的函数,因此不需要保存编译器输出来打孔卡。在Self被Sun公司抛弃后,研究转向了Java语言。“即时编译”这个术语是从制造术语“及时”中借来的,并由Java普及,Java之父James Gosling从1993年开始使用这个术语。目前,大多数Java虚拟机的实现都使用JIT技术,而且使用广泛。

了解JVM的都知道,Java的编译分为两部分:

  • javac.java文件编译为.class文件,即转换为字节码
  • 解释器.class字节码文件解释为机器码(0、1)执行

但是解释执行的缺点很明显,执行速度慢。

Java早期使用解释执行,将字节码逐条解释执行,这种方式运行很慢。如果是快速反复调用某段代码,执行效率大大降低。后来为了解决这种问题,JVM引入了JIT即时编译,当Java虚拟机发现某段代码块或是方法执行比较频繁,超过设定的阈值时,就会把这些代码视为热点代码(Hot Spot code)

为了提高热点代码的执行效率,虚拟机会将其编译为机器码,并存到CodeCache里,等到下次再执行这段代码时,直接从CodeCache里取,直接执行,大大提升了运行效率,整个执行过程如下:

看上图很容易理解JIT是什么,然后思考下面的问题:

  • • 怎么判断属于热点代码?
  • • 阈值是怎么设定的?
  • • codeCache又是什么?

怎么判断热点代码

我们知道JIT是将热点代码编译成机器码缓存起来的,那么什么样的代码才属于热点代码呢

HotSpot虚拟机使用的是基于计数器的热点代码探测,JVM统计每个方法调用栈的弹出频率作为指标,提供了2种次数级别热点探测方法:

  1. 1. 精确计数,超过阈值触发编译 (统计的是总调用量)
  2. 2. 记录一段时间内被调用的次数,超过阈值触发编译(类似QPS的含义)

JVM默认使用的第二种方法统计方法调用次数,因为第一种方法计算开销大,第二种方法与调用时间有关,适用于大多数场景

阈值如何设定

上面说到超过阈值才触发编译,阈值是设置为多少了呢?

先说说JVM的分层编译器,Hotspot虚拟机中,JIT有2种编译器C1编译器(客户端模式)、C2编译器(服务端模式)。

C1编译器:简单快速,搜集信息较少,主要关注点在局部化的优化,编译速度快,适用于对启动性能有要求的应用。缺点是编译后的代码执行效率低;

C2编译器:需要搜集大量的统计信息在编译时进行优化,为长期运行的应用程序做性能优化的编译器,优化手段复杂,编译时间长,编译出来的机器码执行效率高。代价是启动时间变长,程序需要执行较长时间后,才能达到最佳性能;

JAVA8之后默认开启了分层编译,即:应用启动初期使用C1编译器缓存热点代码,在系统稳定后使用C2编译器继续优化性能。

可通过一些参数进行设置

在 Java8 中默认开启分层编译(-XX:+TieredCompilation默认为true)

  • • 如果只想用 C1,可以在打开分层编译的同时使用参数“-XX:TieredStopAtLevel=1”
  • • 如果只想用 C2,使用参数“-XX:-TieredCompilation=false”关闭分层编译即可

通过java -version可看到当前JVM使用的编译模式

方法被调用的次数,在 C1 模式下默认阈值是 1500 次,在 C2 模式是 10000 次,可通过参数-XX: CompileThreshold 手动设定,在分层编译的情况下,-XX: CompileThreshold 指定的阈值将失效,此时将会根据当前待编译的方法数以及编译线程数来动态调整。超过阈值触发编译,编译完成后系统会把方法调用入口改为最新地址,下次直接使用机器码。

需要注意的是,计数器统计的是一段时间内的调用次数,当超过时间限度调用次数仍然未达到阈值,那么该方法的调用次数就会减半,并不是一直累加的,这段时间称为该方法的统计半衰周期,可以使用虚拟机参数-XX:-UseCounterDecay 关闭热度衰减,参数-XX:CounterHalfLifeTime 设置半衰周期的时间,需要注意进行热度衰减的动作是在虚拟机进行垃圾收集时顺便进行的。

CodeCache是什么

CodeCache主要用于存储JIT编译后的机器码,随着程序的运行,大部分热点代码都会编译为机器码来运行。所以Java的运行速度比较快,除了JIT编译的代码外,本地方法代码(JNI)也会存储在Codecache内。可配置一些参数设置Codecache的属性

  • • -XX:ReservedCodeCacheSize:codeCache最大大小
  • • -XX:InitialCodeCacheSize:codeCache初始大小

Linux环境下,Codecache默认大小是2.4375M,可通过jinfo -flag InitialCodeCacheSize [java进程ID]查看,如图

2.为什么应用刚启动时会抖动?

上面已经讲了JIT即时编译,这样也好理解为什么刚启动完的应用,RT突然升高,CPU利用率也很高。在高并发场景下,一个方法的调用次数激增,会瞬间达到JIT编译的阈值,JVM会执行即时编译,讲热点代码转为机器码。热点代码过多时,JIT编译的压力会增大,造成系统的load升高,CPU利用率跟着升高,导致服务的整体性能下降

3.解决方案

这里小卷列了一些解决方案,需要根据具体场景具体使用,如图

JWarmup

AJDK内嵌的功能模块,相关wiki在阿里的Github上阿里巴巴Dragonwell8用户指南

其原理是先发布beta服务器,等到beta服务器的JIT编译完成后,将热点方法dump下来,然后production环境发布时直接加载dump文件,不需要再进行JIT编译了。从JVM层面解决了该问题,但是接入门槛较高,可能会踩一些坑。

平台预热

借助流量调度平台的能力,小流量预热后再放开,把JIT编译的影响降低。是综合考虑接入成本以及推广维护最合适的方案。这里阿里云微服务引擎MSE已提供功能小流量预热服务,但是是收费的哦~

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-10-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 卷福同学 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
HotSpot逃逸分析
即时编译(Just-In-Time Compilation, JIT)是一种强大的技术,旨在增强基于字节码的语言(如Java、.NET)的运行时性能。它的工作原理是在程序运行过程中动态地将频繁执行的字节码转换成本地机器码,从而大幅提高执行效率。这一过程克服了纯解释执行的性能瓶颈,同时保留了跨平台的灵活性。
终有链响
2024/07/29
1150
HotSpot逃逸分析
基本功 | Java即时编译器原理解析及实践
跟其他常见的编程语言不同,Java将编译过程分成了两个部分,这就对性能带来了一定的影响。而即时(Just In Time, JIT)编译器能够提高Java程序的运行速度。
美团技术团队
2020/11/03
1K0
基本功 | Java即时编译器原理解析及实践
有关JIT你需要知道的
JVM对代码执行的优化可分为运行时(runtime)优化和即时编译器(JIT)优化。 运行时优化主要是解释执行和动态编译通用的一些机制。比如说锁机制(如偏斜锁)、内存分配机制(如TLAB)等。除此之外,还有一些专门用于优化解释执行效率的,比如说模版解释器、内联缓存(inline cache,用于优化虚方法调用的动态绑定)
全菜工程师小辉
2019/08/16
1.1K0
Java 面试——即时编译( JIT )
当我们在写代码时,一个方法内部的行数自然是越少越好,这样逻辑清晰、方便阅读,其实好处远不止如此,通过即时编译,甚至可以提高执行时的性能,今天就让我们好好来了解一下其中的原理。
健程之道
2019/11/02
1.4K0
Java真的是一门编译型的语言吗——即时编译器JIT
我们知道编程语言根据编译及运行过程,主要分为两大阵营:编译型语言 和 解释型语言。前者在运行前需要先通过编译器编译成目标产物(通常来说是机器码),然后才可以运行,一旦代码改动就需要重新编译生产新的产物,代表c/c++,而后者则不需要进行编译,由解释器直接接收用户编写的源代码,逐行逐块地解释执行,即便是在运行过程中也可以动态地修改代码行为,代表JavaScript。
燃192
2023/02/28
5030
Java真的是一门编译型的语言吗——即时编译器JIT
JVM参数这样配置会让你的程序更快更强
Java代码的编译,大家都知道是将.java代码编译成.class文件,这个过程是我们常说的编译,也称为前端编译。实际上Java程序的编译和运行不仅仅是将代码编译成.class文件就可以的,因为机器无法直接运行.class文件,还需要JIT或者解释器将.class文件转换成机器码,这个过程称为运行时编译。今天我们就来深入学习一下运行时编译器是怎么实现对Java代码的优化。
故里
2021/10/08
4760
JVM-执行引擎
JVM设计者们的初衷仅仅只是单纯地为了==满足Java程序实现跨平台特性==,因此避免采用静态编译的方式直接生成本地机器指令,从而诞生了实现解释器在运行时采用逐行解释字节码执行程序的想法。
程序员阿杜
2021/07/14
8270
深入分析JVM执行引擎
相信很多朋友在出国旅游,或者与外国友人沟通的过程中,都会遇到语言不通的烦恼。这时候我们就需要掌握对应的外语或者拥有一部翻译机。而笔者只会中文,所以需要借助一部翻译器才能与不懂中文的外国友人交流。咱们的执行引擎就类似于这部“翻译机”。
知了一笑
2022/11/30
5490
深入分析JVM执行引擎
深入浅出JVM(七)之执行引擎的解释执行与编译执行
本篇文章围绕执行引擎,深入浅出的解析执行引擎中解释器与编译器的解释执行和编译执行、执行引擎的执行方式、逃逸分析带来的栈上分配、锁消除、标量替换等优化以及即时编译器编译对热点代码的探测
菜菜的后端私房菜
2024/10/10
1590
深度探索JFR – JFR详细介绍与生产问题定位落地 – 3. 各种Event详细说明与JVM调优策略(3)
JIT 即时编译可能会遇到编译后的代码缓存占满,或者因为空间有限或者代码设计问题,导致某些关键方法需要重编译导致性能问题,以及因为代码块过大导致编译失败从而性能有问题,这些问题我们可以通过 JFR 中相关的 Event 进行查询。 JFR 对于 Java 开发可以完全替换 JVM 编译日志。
全栈程序员站长
2022/08/11
6320
JIT优化之道
《JIT优化之道》是去年在公司的一次分享,对于公司组织分享我是赞同又不赞同,怎么讲呢?
码农戏码
2021/03/23
1K0
JVM执行引擎(Execution Engine)
机器码是通过各种二进制表示的一串可以被计算机直接运行的指令,这种也叫机器语言,通常用010110这种来表示。虽然容易被计算机理解并且执行速度快,但是与我们所有的语言相关太大,并且维护成本巨大。
逍遥壮士
2021/07/05
1.2K0
JVM执行引擎(Execution Engine)
JVM进阶 -- 浅谈即时编译
假设应用程序调用该方法,所传入的都是true,那么偏移量为1和偏移量为18的条件跳转指令所对应的分支profile中,其跳转的次数都是0。实际执行的分支如下:
用户4283147
2022/10/27
1.1K0
JVM进阶 -- 浅谈即时编译
JVM系列七(JIT 即时编译器).
即时编译器(Just In Time Compiler),也称为 JIT 编译器,它的主要工作是把热点代码编译成与本地平台相关的机器码,并进行各种层次的优化,从而提高代码执行的效率。
JMCui
2020/02/13
1.1K0
从RPC预热转发看服务端性能调优
为了更好的体验和更优的性能,其实RPC悄悄的做了很多工作,本篇就带大家来看下RPC的一些高级特性和其背后的原因。(还是以开源的dubbo和sofa为例来说明)
Bug开发工程师
2021/08/24
6790
从RPC预热转发看服务端性能调优
你编写的Java代码是咋跑起来的?
如果你是一名 Java 开发人员,你肯定指定 Java 代码有很多种不同的运行方式。比如说可以在开发工具(IDEA、Eclipse等)中运行,可以双击执行 jar 文件运行,也可以在命令行中运行,甚至可以在网页(比如各种 OJ)中运行。当然,这些执行方式都离不开 JRE(Java 运行时环境)。
武培轩
2019/11/04
7590
你编写的Java代码是咋跑起来的?
JVM笔记-后端编译与优化
前面分析了 JVM 的前端编译器 Javac,本文分析后端编译器:即时编译器(JIT 编译器)和提前编译器(AOT 编译器)。
WriteOnRead
2020/04/22
6690
JVM笔记-后端编译与优化
浅谈JVM运行期的几种优化手段
在之前的文章中我们谈到过,相比 C/C++ 语言,Java 语言在运行效率方面要稍逊一些,因为 Java 应用程序是在虚拟机上运行,而 C/C++ 程序是直接编译成平台相应的机器码来运行程序。
Java极客技术
2024/03/14
2290
浅谈JVM运行期的几种优化手段
深入浅出了解Java即时编译器原理及实战
学习JVM相关的知识,必然绕不开即时编译器,因为它太重要了。了解了它的基本原理及优化手段,在编程过程中可以让我们有种打开任督二脉的感觉。比如,很多朋友在面试当中还会遇到这样的问题:Java是基于编译执行还是基于解释执行?当你了解了Java的即时编译器,不仅能够轻松回答上述问题,还能如数家珍的讲出JVM在即时编译器上采用的优化技术,而且在实践过程中更深刻的理解代码背后的原理。本文便带大家全面的了解Java即时编译器。
程序新视界
2020/12/31
9470
java官方编译器_JAVA 编译器
说白了,javac就是一个编译器;编译器就是把一种语言规矩转换成另一种语言规矩,也就是将对人友好的语言转换成对机器友好的语言。因此,javac是把Java源代码编译成Java字节码,即JVM可以识别的二进制;表面上就是将.java文件转成.class文件。
全栈程序员站长
2022/09/14
2.4K0
相关推荐
HotSpot逃逸分析
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档