SpringBoot應(yīng)用剛啟動時服務(wù)報大量超時的問題及解決
1、背景
部門剛轉(zhuǎn)Java時,每次項目更新線上的時候,都會報大量超時的問題。
雖然操作非常緩慢且小心,按照摘除負(fù)載、更新容器、等待一段時間、恢復(fù)負(fù)載的嚴(yán)格步驟來操作,Nginx那邊依然會報許多的503超時告警。搞得之后每次更新線上都膽戰(zhàn)心驚。
后來采用了在服務(wù)起來之后,自動調(diào)用所有的接口進(jìn)行預(yù)熱,暫時的解決了這個問題。服務(wù)更新啟動后也不會再報超時的錯誤了。
最近在網(wǎng)上也看到了類似的情況,表現(xiàn)為應(yīng)用在剛剛啟動之后,前幾次訪問都會比較卡頓,RT都會比極高,在運行一段時間之后,就會順暢很多了。
2、原因
看來是SpringBoot應(yīng)用的通病,所以就網(wǎng)上搜集了一波資料,研究下具體的原因。
主要原因是JIT編譯。
我們知道,想要把高級語言轉(zhuǎn)變成計算機認(rèn)識的機器語言有兩種方式,分別是編譯和解釋,雖然Java轉(zhuǎn)成機器語言的過程中有一個步驟是要編譯成字節(jié)碼,但是,這里的字節(jié)碼并不能在機器上直接執(zhí)行。
所以,JVM中內(nèi)置了解釋器(interpreter),在運行時對字節(jié)碼進(jìn)行解釋翻譯成機器碼,然后再執(zhí)行。
解釋器的執(zhí)行方式是一邊翻譯,一邊執(zhí)行,因此執(zhí)行效率很低。為了解決這樣的低效問題,HotSpot引入了JIT技術(shù)(Just-In-Time)。
JIT 代表即時編譯(Just In Time compilation),當(dāng)代碼執(zhí)行的次數(shù)超過一定的閾值時,會將 Java 字節(jié)碼轉(zhuǎn)換為本地代碼,如,主要的熱點代碼會被準(zhǔn)換為本地代碼,這樣有利大幅度提高 Java 應(yīng)用的性能。
有了JIT技術(shù)之后,JVM還是通過解釋器進(jìn)行解釋執(zhí)行。但是,當(dāng)JVM發(fā)現(xiàn)某個方法或代碼塊運行時執(zhí)行的特別頻繁的時候,就會認(rèn)為這是“熱點代碼”(Hot Spot Code)。然后JIT會把部分“熱點代碼”翻譯成本地機器相關(guān)的機器碼,并進(jìn)行優(yōu)化,然后再把翻譯后的機器碼緩存起來,以備下次使用。
這也是HotSpot虛擬機的名字的由來。
大家理解了JIT編譯的原理之后,其實可以知道,JIT優(yōu)化是在運行期進(jìn)行的,并且也不是Java進(jìn)程剛一啟動就能優(yōu)化的,是需要先執(zhí)行一段時間的,因為他需要先知道哪些是熱點代碼。
所以,在IT優(yōu)化開始之前,我們的所有請求,都是要經(jīng)過解釋執(zhí)行的,這個過程就會相對慢一些。
而且,如果你們的應(yīng)用的請求量比較大的的話,這種問題就會更加明顯,在應(yīng)用啟動過程中,會有大量的請求過來,這就會導(dǎo)致解釋器持續(xù)的在努力工作。
一旦解釋器對CPU資源占用比較大的話,就會間接的導(dǎo)致CPU、LOAD等飆高,導(dǎo)致應(yīng)用的性能進(jìn)一步下降。
這也是為什么很多應(yīng)用在發(fā)布過程中,會出現(xiàn)剛剛重啟好的應(yīng)用會發(fā)生大量的超時問題了。
而隨著請求的不斷增多,JIT優(yōu)化就會被觸發(fā),這就是使得后續(xù)的熱點請求的執(zhí)行可能就不需要在通過解釋執(zhí)行了,直接運行JIT優(yōu)化后緩存的機器碼就行了。
3、解決
那么,怎么解決這樣的問題呢?
主要有兩種思路:
- 1、提升JIT優(yōu)化的效率
- 2、降低瞬時請求量
在提升JIT優(yōu)化效率的設(shè)計上,大家可以了解一下阿里研發(fā)的JDK——Dragonwell。
這個相比OpenJDK提供了一些專有特性,其中一項叫做JwarmUp的技術(shù)就是解決JIT優(yōu)化效率的問題的。
這個技術(shù)主要是通過記錄Java應(yīng)用上一次運行時候的編譯信息到文件中,在下次應(yīng)用啟動時,讀取該文件,從而在流量進(jìn)來之前,提前完成類的加載、初始化和方法編譯,從而跳過解釋階段,直接執(zhí)行編譯好的機器碼。
除了針對JDK做優(yōu)化之外,還可以采用另外一種方式來解決這個問題,那就是做預(yù)熱。
很多人都聽說過緩存預(yù)熱,其實思想是類似的。
就是說在應(yīng)用剛剛啟動的時候,通過調(diào)節(jié)負(fù)載均衡,不要很快的把大流量分發(fā)給他,而是先分給他一小部分流量,通過這部分流量來觸發(fā)JIT優(yōu)化,等優(yōu)化好了之后,再把流量調(diào)大。
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
- SpringBoot中@Scheduled實現(xiàn)服務(wù)啟動時執(zhí)行一次
- idea啟動多個SpringBoot服務(wù)實例的最優(yōu)解決方法
- springboot項目同時啟動web服務(wù)和grpc服務(wù)的方法
- centos7如何通過systemctl啟動springboot服務(wù)代替java -jar方式啟動
- IDEA中啟動多個SpringBoot服務(wù)的實現(xiàn)示例
- springboot服務(wù)正常啟動之后,訪問服務(wù)url無響應(yīng)問題及解決
- springboot項目如何在linux服務(wù)器上啟動、停止腳本
- 解決springboot服務(wù)啟動報錯:Unable?to?start?embedded?contain
相關(guān)文章
解決springboot?部署到?weblogic?中?jar?包沖突的問題
這篇文章主要介紹了springboot?部署到?weblogic?中?jar?包沖突,weblogic?也有是解決方案的,可以通過新增并配置?weblogic.xml?文件來定義哪些類需要優(yōu)先從項目工程包的?jar?包中加載,本文給大家分享解決方法,需要的朋友可以參考下2022-08-08解決MyBatis返回結(jié)果類型為Boolean的問題
這篇文章主要介紹了解決MyBatis返回結(jié)果類型為Boolean的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-11-11