1 問題
? ? ?最近,在某個高QPS的服務在重啟的時候,如圖1.1所示,重啟會load 非常高,出現尖刺,短信報警CPU使用率過高,然后一段時間負載就降下來。搜索下網絡的文章,啟動后高負載的原因大致是由于啟動,隨著代碼的執行,jvm的jit編譯器會將部分熱點代碼編譯為目標機器代碼,這時產生的編譯線程會占用大量的cpu 導致系統負載高。但是通過top -H -p 查看編譯線程的cpu 使用率,發現cpu 使用率比其他線程略高,但是沒有明顯差距,但是比較其他的請求線程,加在一起的cpu 使用率還是很可觀。所以在此懷疑,JIT編譯器需要代碼執行一定的頻率才會進行編譯優化,系統剛啟動的時候大部分的代碼只是解釋執行,解釋執行的性能比編譯執行的性能當然要差很多,所以系統的負載高,等到主要熱點代碼都是編譯執行,系統負載就降下來。 那接下來如何對這個問題調優呢?
2 ?jvm ?調優
? 針對上面的問題,有兩個解決方案:
? 2.1 純編譯執行(-Xcomp)
? ? ?jvm提供了一個參數-Xcomp ,這個參數可以使jvm運行在純編譯的模式,所有的方法在第一次調用的時候就會編成機器代碼,但是現實的話,設置了這個參數之后系統啟動負載的確沒有上升,這驗證了我們之前的猜測,但是隨之而來的問題,啟動的時間是原來的兩倍多,這對我們的應用是不好接受的,現在我們應用啟動時間都快到3分鐘。所以純編譯不是我們的最優選擇。不過,我們還有分層編譯。
2.2 分層編譯(-XX:+TieredCompilation)
? ? ?除了純編譯和默認的mixed之外,jvm 從jdk6u25 之后,引入了分層編譯。HotSpot 內置兩種編譯器,分別是client啟動時的c1編譯器和server啟動時的c2編譯器,c2在將代碼編譯成機器代碼的時候需要搜集大量的統計信息以便在編譯的時候進行優化,因此編譯出來的代碼執行效率比較高,代價是程序啟動時間比較長,而且需要執行比較長的時間,才能達到最高性能;與之相反, c1的目標是使程序盡快進入編譯執行的階段,所以在編譯前需要搜集的信息比c2要少,編譯速度因此提高很多,但是付出的代價是編譯之后的代碼執行效率比較低,但盡管如此,c1編譯出來的代碼在性能上比解釋執行的性能已經有很大的提升,所以所謂的分層編譯,就是一種折中方式,在系統執行初期,執行頻率比較高的代碼先被c1編譯器編譯,以便盡快進入編譯執行,然后隨著時間的推移,執行頻率較高的代碼再被c2編譯器編譯,以達到最高的性能。
3 效果
? 線上環境一臺機器加入分層編譯參數-XX:+TieredCompilation之后,如圖3.1效果很明顯,在大多數情況下啟動之后負載都不會升高,有時候即使有會升高,也比默認的恢復快很多。