3 回答
TA貢獻1951條經(jīng)驗 獲得超3個贊
我們的微服務遇到了類似的問題,為了預熱我們添加了一個組件
ApplicationStartup implements ApplicationListener<ApplicationReadyEvent>
在應用程序啟動后立即在應用程序中調用服務,這對我們有用。使用此解決方案,可以保證將在您的有效負載中使用的所有類將在您啟動的每個實例中的實例啟動后立即加載,并且您不需要外部腳本來進行調用。外部腳本也有問題,我們不能確定調用由新實例處理。
@Component
public class ApplicationStartup implements ApplicationListener<ApplicationReadyEvent> {
@Autowired
YourService yourService;
@Override
public void onApplicationEvent(final ApplicationReadyEvent event) {
System.out.println("ApplicationReadyEvent: application is up");
try {
// some code to call yourservice with property driven or constant inputs
} catch (Exception e) {
e.printStackTrace();
}
}
}
TA貢獻1802條經(jīng)驗 獲得超5個贊
如果您的應用程序在您向其提供請求時是健康的,但您仍然遇到響應緩慢的問題,您應該嘗試啟用分層編譯
-XX:CompileThreshold -XX:TieredCompilation
通常,VM 使用解釋器來收集有關提供給編譯器的方法的分析信息。在分層方案中,除了解釋器之外,客戶端編譯器還用于生成方法的編譯版本,這些方法收集有關自身的分析信息。
由于編譯代碼比解釋代碼快得多,因此程序在分析階段以更好的性能執(zhí)行。
TA貢獻1942條經(jīng)驗 獲得超3個贊
這個問題可以從兩個方面來解決。第一種方法是上菜前先熱身。第二種方法是一開始就少給外部的請求,這樣可以預留更多的計算資源來完成JVM的一些初始化(比如類加載)。無論哪種方式,都是因為 JVM 需要預熱才能啟動。這是由JVM的運行原理決定的。特別是HotSpot虛擬機,其執(zhí)行引擎由解釋執(zhí)行引擎和實時編譯執(zhí)行(JIT)兩部分組成。對于 JIT,需要 CPU 資源來實時編譯字節(jié)碼。此外,類的延遲加載在第一次運行時也會需要更多時間。
JVM 預熱
JVM預熱主要是解決類加載和實時編譯兩個問題。
對于類加載,只需提前運行覆蓋代碼路徑。
對于JIT來說,C1/C2等分層編譯一般是在服務器端開啟的(JVM服務器模式)。如果你使用JDK7或以上版本,默認開啟分層編譯(JDK低版本需要JVM參數(shù):-XX:+TieredCompilation),C1和C2的編譯計算資源不同,C2會有更多。預熱的目的可能是觸發(fā)C1/C2編譯,這樣當官方請求進來時,代碼已經(jīng)預熱編譯通過。
對于以上兩個方向,類加載本身會消耗更多的時間。熱身這部分會得到更大的投入產(chǎn)出比。
網(wǎng)絡層預熱。
從網(wǎng)絡層面,給定一定的預熱流量,可以是特定的預熱流量,也可以是普通的用戶請求。
這通??梢栽?nginx 層進行流量控制。當一個新啟動的節(jié)點加入上游時,可以給新節(jié)點一個非常低的權重。這樣,在初始階段只進入了少量的流量。因此,預留了足夠的計算資源。做代碼預熱,即類加載和即時編譯。如果服務只提供 RPC 服務,不提供 HTTP 服務,則 RPC 框架層可以做流量預熱。例如,Dubbo 等 RPC 框架已經(jīng)具備服務預熱功能。同樣,預熱意味著啟動初期的節(jié)點只給少量的流量。
預熱所需的計算資源在上述方法中都有提及。也就是CPU。如果您的服務主機有足夠的計算資源,您可以為每個節(jié)點分配更多的 CPU 資源,以加快預熱過程。減少預熱處理時間。
如果上述網(wǎng)絡層和硬件資源和RPC框架不能改變。我們可以在 SpringBoot 微服務中熱身。上面的答案已經(jīng)提到ApplicationReadyEvent,實際更好的實現(xiàn)是監(jiān)聽ContextRefreshedEvent事件。因為 HTTP 端口會在 ApplicationReadyEvent 發(fā)生時被初始化和暴露。在預熱完成之前可能會有意外的請求進來。
@Component
public class StartWarmUpListener implements ApplicationListener<ContextRefreshedEvent> {
/**
* Handle an application event.
*
* @param event the event to respond to
*/
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
// do something about warm-up here.....
}
}
注意:上面的預熱代碼并沒有預熱所有代碼。因為Controller層的請求有一些代碼路徑,直到HTTP服務器沒有準備好才能真正執(zhí)行。我們只能在服務層進行代碼覆蓋。簡而言之,這可能是一種妥協(xié)。
添加回答
舉報
