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