JVM 检查点恢复

Spring 框架与 Project CRaC 实现的检查点/恢复功能集成,以允许实现能够减少基于 Spring 的 Java 应用程序的 JVM 启动和预热时间的系统。

使用此功能需要

  • 启用了检查点/恢复的 JVM(目前仅限 Linux)。

  • 类路径中存在 org.crac:crac 库(支持 1.4.0 及更高版本)。

  • 指定所需的 java 命令行参数,例如 -XX:CRaCCheckpointTo=PATH-XX:CRaCRestoreFrom=PATH

当请求检查点时,在 -XX:CRaCCheckpointTo=PATH 指定的路径中生成的文

从概念上讲,检查点和恢复与各个 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。