优质博文:IT-BLOG-CN
一、背景
业务流量突增,机器直接接入大量流量QPS2000
,JIT
和GC
会消耗太多CPU
资源,导致1-2分钟时间内的请求超时导致异常,因此采用流量预热的方式,让机器逐步接入流量,需要预热时长3min
。目前服务接入HPA
,通过HPA
自动扩缩容应用流量变化,当流量激增时,对机器的启动速度带来了挑战,之前通过Swift
优化点火时间,已经将机器从容器创建到可接入流量优化到2分钟左右,但3min的预热时长成为了应对流量激增的瓶颈,因此优化机器从接入流量到能稳定服务的时长,目标缩减到2min以内。
什么是服务预热: Java
应用在刚启动的时候处理相应速度会很慢,只有当热点代码执行了一定次数以后,相应速度才会达到一个稳定状态。由于Java
慢启动现象的存在,多数情况下我们有必要对Java
应用进行预热,以防止客户端在调用过程中,因为服务器重启或发布事件,而出现大量慢请求。
流量接入后younggc
耗时:峰值900ms
左右,最大次数18次
二、优化思路
名词解释
JIT(Just In Time)
即时编译器: java
程序是解释执行的,即运行时将字节码解释为机器码来执行,因此性能差;为了优化Java
性能,jvm
引入的编译器,随着程序的执行,编译器会将热点代码编译优化为本地代码,来获取更高的执行效率
jvm
中集成了两种编译器:
【1】Client Compiler
:如C1
编译器,注重启动速度和局部的优化,C1
的启动速度开,但是峰值性能比C2
要差;
【2】Server Compiler
:如C2
编译器、Graal
编译器,关注全局的优化,性能会更好,但由于会进行更多的全局分析,所以启动速度会变慢;
【3】分层编译:为了综合Client Complier
和Server Compiler
的特性,在启动速度和峰值性能之间取得平衡,java7
开始引入分层编译,分为5
层:
■ 解释执行。
■ 执行不带profiling
的C1
代码。
■ 执行仅带方法调用次数以及循环回边执行次数profiling
的C1
代码。
■ 执行带所有profiling
的C1
代码。
■ 执行C2
代码。
方法内联: 编译过程中遇到方法调用时,将目标方法的方法体纳入编译范围之中,并取代原方法调用的优化手段,JIT
大部分的优化都是在内联的基础上进行的;
逃逸分析: 编译器,根据新建对象是否被存入堆中以及是否传入未知代码(未内联代码)中,判断对象是否逃逸&#x