Spring Boot + CRaC 启动速度提升了10倍!

在 Java 应用程序的开发与运行过程中,启动和预热时间过长一直是个令人头疼的难题。目前,业界也提出了不少解决思路,之前我和大家探讨过的 AOT 技术,能在一定程度上缓解启动慢的问题。

今天,咱们要聊的 CRaC 技术,为这个问题提供了另一种全新的解决方案。

一、CRaC 是什么

CRaC,即 Coordinated Restore at Checkpoint(检查点协调恢复),是一个 OpenJDK 项目。它具备一项强大的功能,允许我们对正在运行的 JVM 进行"快照"操作,并将其状态(包括应用程序的状态)存储到磁盘当中。

在后续需要的时候,我们可以将 JVM 从之前保存的检查点恢复到内存里。这意味着,我们可以先启动应用程序,进行预热,然后创建检查点。之后再启动应用时,直接从这个检查点快速恢复,从而大幅减少启动时间。关注公众号:码猿技术专栏,回复关键词:1111 获取阿里内部Java性能调优手册!

这就好比我们平时使用 VMWare 时的快照功能。我们在某个时间点为系统拍摄一个快照,下次启动时直接从快照启动,比从头开始启动要快得多。而且 CRaC 所拍摄的快照中,不仅包含 JVM 的信息,还涵盖了应用程序的相关信息。

二、CRaC 的原理

CRaC 的工作原理基于用户空间检查点和恢复(CRIU)技术。CRIU 是一个专门为 Linux 系统实现检查点和恢复功能的项目,它允许我们冻结容器或者单个应用程序,并从保存的检查点文件中恢复它。

CRaC 采用了 CRIU 的通用方法,同时进行了一些增强和调整,使其更适合 Java 应用程序。一般来说,CRaC 的执行步骤如下:

  1. 创建检查点:当应用程序运行并达到稳定状态后,我们可以创建一个检查点。这个检查点包含了 JVM 的当前状态以及应用程序的数据。
  2. 存储检查点:将创建好的检查点数据存储到磁盘上,方便后续从中恢复。
  3. 恢复检查点:当需要启动应用程序时,我们可以直接从检查点恢复,而无需从头开始启动和预热 JVM。

三、CRaC 的应用场景

CRaC 特别适用于那些需要快速启动和恢复的场景,以下是一些具体的应用场景:

  • 云原生环境:在微服务和无服务器架构中,服务可能需要频繁地启动和停止。CRaC 可以显著减少服务的启动时间,提高系统的响应速度和资源利用率。
  • 开发和测试环境:开发者在开发和测试过程中,可以利用 CRaC 快速恢复应用程序到某个已知状态,大大提高开发效率。
  • 灾难恢复:当系统发生故障时,我们可以借助 CRaC 快速从最近的检查点恢复服务,减少系统的停机时间,降低损失。

四、支持版本

从 Spring Boot 3.2/Spring 6.1 开始,Spring 框架对 CRaC 提供了支持。所以,如果大家想要体验 CRaC 技术,需要选择合适的 Spring Boot 版本。

同时,由于 CRaC 依赖于 Linux 特有的 CRIU 技术,因此目前 CRaC 仅在 Linux 操作系统上支持,Windows 和 Mac 系统暂不支持。

五、实践

安装支持 CRaC 的 JDK

首先,我们需要安装支持 CRaC 的 JDK。目前主要有以下两种 JDK 支持 CRaC:

  1. Azul Zulu 21.0.1 + CRaC 版本支持 CRaC,适用于 x64 和 aarch64 CPU 架构,包括 JDK 17 和 JDK 21。
  2. Liberica JDK 17 和 Liberica JDK 21 也提供了对 CRaC 的支持。

添加 CRaC 依赖

安装好 JDK 后,我们需要在项目中添加 CRaC 依赖。在项目的 pom.xml 文件中添加以下代码:

xml 复制代码
<dependency>
    <groupId>org.crac</groupId>
    <artifactId>crac</artifactId>
    <version>1.5.0</version>
</dependency>

添加完依赖后,我们的准备工作就基本完成了。

指定检查点位置和生成时机

接下来,我们需要在项目启动的时候,指定检查点的位置,并确定生成检查点的时机。有两种方式可以实现:

自动检查点

使用以下命令启动应用程序:

shell 复制代码
java -Dspring.context.checkpoint=onRefresh -XX:CRaCCheckpointTo=./tmp_checkpoint -jar javaboy-crac-3.3.5.jar

在这个启动脚本中,我们通过设置 JVM 系统属性 -Dspring.context.checkpoint=onRefresh 来启用自动检查点。这个属性会在 Spring 的 LifecycleProcessor.onRefresh 阶段自动创建检查点。这个阶段是在所有非延迟初始化的 Singleton 实例化和 InitializingBean#afterPropertiesSet 回调调用之后,但在生命周期启动和 ContextRefreshedEvent 发布之前。也就是说,在这个时机创建检查点(拍摄快照)。

手动检查点

如果你想等应用程序完全启动之后再拍摄快照,可以先用以下命令启动应用程序:

shell 复制代码
java -XX:CRaCCheckpointTo=./tmp_checkpoint -jar javaboy-crac-3.3.5.jar

等待应用程序完全启动后,在另一个终端执行以下命令来手动触发检查点:

shell 复制代码
jcmd <pid> JDK.checkpoint

其中 <pid> 是应用程序的进程 ID。执行这个命令后,系统将创建检查点并关闭应用程序。检查点文件将存储在指定的文件夹中。手动执行检查点生成的好处是,这个检查点包含了框架代码和应用程序代码,因此启动速度会更快,因为框架已经加载并启动了应用程序。

使用检查点快速拉起应用程序

无论采用哪种方式生成检查点,只要有了检查点文件,我们就可以利用它来快速拉起应用程序。使用以下命令:

shell 复制代码
java -XX:CRaCRestoreFrom=./tmp_checkpoint

综上所述,自动检查点适合快速实现且无需代码更改的场景,而手动检查点则提供了更大的灵活性,允许我们在应用程序完全预热后创建检查点,从而可能实现更快的启动时间。

相关推荐
舒一笑3 分钟前
🚀 我用一行命令,把 OSS 私有文件变成“可直接下载的公网链接”(很多人不会)
后端
yyt3630458415 分钟前
spring单例bean线程安全问题讨论
java·spring
小兔崽子去哪了15 分钟前
Docker 安装 PostgreSQL
数据库·后端·postgresql
Sweet锦16 分钟前
SpringBoot 3.5 集成 InfluxDB 1.8
spring boot·时序数据库
野犬寒鸦19 分钟前
Redis热点key问题解析与实战解决方案(附大厂实际方案讲解)
服务器·数据库·redis·后端·缓存·bootstrap
我是大猴子26 分钟前
事务失效的几种情况以及是为什么(详解)
java·开发语言
snakeshe10101 小时前
深入理解 Java 注解:从原理到实战
后端
Lucaju1 小时前
吃透 Spring AI Alibaba 多智能体|四大协同模式+完整代码
后端
Nyarlathotep01131 小时前
Redis的对象(5):有序集合对象
redis·后端
wertyuytrewm1 小时前
Java面试——Java基础
java·jvm·面试