JVM 檢查點恢復
Spring Framework 集成了由 Project CRaC 實現的檢查點/恢復功能,旨在透過 JVM 降低基於 Spring 的 Java 應用程式的啟動和預熱時間。
使用此功能需要:
-
啟用檢查點/恢復的 JVM(目前僅限 Linux)。
-
類路徑中存在
org.crac:crac庫(支援版本1.4.0及以上)。 -
指定必需的
java命令列引數,例如-XX:CRaCCheckpointTo=PATH或-XX:CRaCRestoreFrom=PATH。
當請求檢查點時,在 -XX:CRaCCheckpointTo=PATH 指定的路徑中生成的檔案包含執行中的 JVM 記憶體表示,其中可能包含秘密和其他敏感資料。使用此功能時應假定 JVM “看到” 的任何值,例如來自環境的配置屬性,都將儲存在這些 CRaC 檔案中。因此,應仔細評估這些檔案的生成、儲存和訪問位置和方式所帶來的安全隱患。 |
從概念上講,檢查點和恢復與單個 bean 的 Spring Lifecycle 契約保持一致。
執行中應用程式的按需檢查點/恢復
可以按需建立檢查點,例如使用 jcmd application.jar JDK.checkpoint 等命令。在建立檢查點之前,Spring 會停止所有正在執行的 bean,透過實現 Lifecycle.stop 讓他們有機會在需要時關閉資源。恢復後,相同的 bean 會重新啟動,Lifecycle.start 允許 bean 在相關時重新開啟資源。對於不依賴 Spring 的庫,可以透過實現 org.crac.Resource 並註冊相關例項來提供自定義檢查點/恢復整合。
| 利用執行中應用程式的檢查點/恢復通常需要額外的生命週期管理,以優雅地停止和啟動使用檔案或套接字等資源,並停止活動執行緒。 |
請注意,當以固定速率定義排程任務時,例如使用 @Scheduled(fixedRate = 5000) 等註解,檢查點和恢復之間所有錯過的執行都將在 JVM 恢復後透過按需檢查點/恢復執行。如果這不是您想要的行為,建議以固定延遲(例如使用 @Scheduled(fixedDelay = 5000))或使用 cron 表示式來排程任務,因為這些會在每次任務執行後計算。 |
| 如果在已預熱的 JVM 上建立檢查點,則恢復的 JVM 也將同樣預熱,從而可能立即達到峰值效能。此方法通常需要訪問遠端服務,因此需要一定程度的平臺整合。 |
啟動時的自動檢查點/恢復
當設定 -Dspring.context.checkpoint=onRefresh JVM 系統屬性時,會在啟動期間的 LifecycleProcessor.onRefresh 階段自動建立檢查點。此階段完成後,所有非延遲初始化的單例都已例項化,並且 InitializingBean#afterPropertiesSet 回撥已呼叫;但生命週期尚未開始,並且 ContextRefreshedEvent 尚未釋出。
出於測試目的,還可以利用 -Dspring.context.exit=onRefresh JVM 系統屬性,該屬性會觸發類似的行為,但不是建立檢查點,而是在相同的生命週期階段退出 Spring 應用程式,而無需 Project CraC 依賴項/JVM 或 Linux。這對於檢查在 bean 未啟動時是否需要連線到遠端服務,並可能最佳化配置以避免這種情況非常有用。
| 如上所述,尤其是在 CRaC 檔案作為可部署工件(例如容器映象)的一部分進行交付的用例中,請假定 JVM “看到” 的任何敏感資料最終都會儲存在 CRaC 檔案中,並仔細評估相關的安全隱患。 |
| 自動檢查點/恢復是一種“快進”應用程式啟動到應用程式上下文即將啟動的階段的方法,但它不允許擁有完全預熱的 JVM。 |