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 文件中。因此,应仔细评估这些文件的生成、存储和访问位置和方式的安全影响。
从概念上讲,检查点和恢复与 Spring Lifecycle
契约 对单个 bean 的对齐。
运行中应用程序的按需检查点/恢复
可以按需创建检查点,例如使用 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。 |