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 檔案作為可部署 artifact(例如容器映象)一部分交付的使用場景中,應假設 JVM "看到" 的任何敏感資料最終都會存入 CRaC 檔案中,並仔細評估相關的安全影響。 |
自動檢查點/恢復是一種將應用啟動“快進”到應用上下文即將啟動階段的方式,但它不能實現完全預熱的 JVM。 |