CRaC 是一个 OpenJDK 项目,可以对运行中的 JVM(Java 虚拟机)进行 "快照",并将其状态(包括应用程序)存储到磁盘中。然后,在另一个时间点,您可以将 JVM 从保存的检查点恢复到内存中。这样,就可以启动应用程序、预热并创建检查点。从保存的检查点恢复到内存主要依靠磁盘 I/O,这意味着恢复速度非常快(在毫秒级范围内)。
为了测试 SpringBoot 3.2 对 CRaC 的支持,我将使用 SpringBoot Petclinic 演示。
在这个小测试中,我在使用 4 核和 4GB 内存的 M1 Macbook Pro 上通过 Parallels 运行 Ubuntu 22.04。
要在 SpringBoot 3.2 中使用 CRaC,需要具备三个条件:
- 支持 CRaC 的 JVM
- org.crac 的依赖关系
- 可存储检查点的文件夹
1、支持 CRaC 的 JVM
使用的 JDK(Java 开发工具包)是 Azul Zulu 21.0.1 + CRaC,您可以在此处获取。JDK 适用于 x64 和 aarch64 CPU 架构以及 JDK 17 和 JDK 21。
可能需要设置权限才能使用 CRIU,也就是说在运行演示的 Linux 机器上,您需要执行一次以下命令:
sudo chown root:root $JAVA_HOME/lib/criu |
由于 CRaC 目前仅在 Linux 上可用,因此您找不到支持 MacOS 和 Windows 的 CRaC 的 JDK。
org.crac 库
有了org.crac 库,您甚至可以在 MacOS 和 Windows 上针对 CRaC API 进行编码,而不会出现任何问题,并且一旦您在具有启用 CRaC 的 JDK 的 Linux 系统上运行它,它将使用 CRaC 功能。
org.crac 库提供了与支持 CRaC 的 JDK 中可用的相同 API,但您将在“org.crac”命名空间中找到它,而不是使用“jdk.crac”命名空间。
导入:
<dependency> |
2、为检查点创建文件夹
在测试之前,我们需要确保有一个可以存放检查点的文件夹,例如项目文件夹中的 /tmp_checkpoint。
3、自动检查点
Spring 团队的工程师们有一个好主意,那就是在应用程序启动前自动创建一个检查点,从而缩短 Spring/SpringBoot 框架的启动时间。
以下是文档中的描述:
"当设置了 -Dspring.context.checkpoint=onRefresh JVM 系统属性时,启动时会在 LifecycleProcessor.onRefresh 阶段自动创建检查点。该阶段完成后,所有非懒惰初始化单子都已实例化,InitializingBeanafterPropertiesSet 回调也已调用;但生命周期尚未启动,ContextRefreshedEvent 尚未发布。"
为了使用自动检查点功能,我们按如下方式启动应用程序:
java -Dspring.context.checkpoint=onRefresh -XX:CRaCCheckpointTo=./tmp_checkpoint -jar spring-petclinic-3.2.0.jar |
执行程序后,它会创建检查点,将检查点文件存储在 ./tmp_checkpoint 文件夹中,然后退出程序。
现在,你可以通过执行以下命令从检查点恢复应用程序(这意味着再次启动它):
java -XX:CRaCRestoreFrom=./tmp_checkpoint |
我们无需修改代码就能获得比原始启动时间快一个数量级的启动时间。这也意味着检查点只包含框架代码,而不包含应用程序代码,因为应用程序代码尚未启动。
总结
使用 CRaC 可以显着减少 SpringBoot 3.2 应用程序的启动时间。如果您只是想在不接触代码的情况下尝试一下,只需使用 Spring 6.1 / SpringBoot 3.2 中的自动检查点功能即可将启动时间减少一个数量级。
CRaC 的优点在于它仍然在普通 JVM 上运行,并且在检查点/恢复后代码甚至可以进一步优化。
为了尽可能缩短启动时间,您可以手动创建检查点,这可以将启动时间缩短两个数量级。
源码:GitHub 存储库