3

构建第一个GraalVM应用镜像,体验毫秒级极速启动!

 11 months ago
source link: https://www.51cto.com/article/769114.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

构建第一个GraalVM应用镜像,体验毫秒级极速启动!

作者:迷路的架构师 2023-10-09 14:32:48

GraalVM使用其Ahead-Of-Time(AOT)编译器将Java应用程序编译为机器可执行文件。这些可执行文件可以直接在目标机器上执行,而无需使用即时编译器(JIT)。

57f561f30a832de93751220496c6f1729d6afe.jpg

GraalVM使用其Ahead-Of-Time(AOT)编译器将Java应用程序编译为机器可执行文件。这些可执行文件可以直接在目标机器上执行,而无需使用即时编译器(JIT)。GraalVM生成的二进制文件体积较小,启动速度快,并且在没有任何预热的情况下提供最佳性能。此外,这些可执行文件的内存占用和CPU使用率低于在JVM上运行的应用程序。

Docker允许我们将软件组件打包成Docker镜像,并作为Docker容器运行。Docker容器包含应用程序运行所需的一切,包括应用代码、运行时、系统工具和库。

在本文中,我们创建一个Java应用程序的GraalVM原生镜像,并将其作为Docker容器运行。

什么是原生镜像?

原生镜像是一种将Java代码提前编译成本地可执行文件的技术。这个本地可执行文件只包含在运行时需要执行的代码,包括应用程序类、标准库类、语言运行时以及来自JDK的静态链接的本机代码。

原生镜像构建器(native-image)扫描应用程序类和其他元数据,来创建特定于操作系统和架构的二进制文件。native-image工具对应用程序代码进行静态分析,确定在应用程序运行时可达到的类和方法。然后,它将所需的类、方法和资源编译成一个二进制可执行文件。

原生镜像的好处

原生镜像可执行文件具有以下几个优点:

  • 由于原生镜像构建器仅编译运行时所需的资源,因此可执行文件较小。
  • 原生可执行文件具有非常快的启动时间,因为它们在目标机器上直接执行,而无需使用JIT编译器。
  • 由于只打包所需的应用程序资源,提供了较小的被攻击面。
  • 适用于打包到轻量级容器镜像(例如Docker镜像)中,以实现快速高效的部署。

构建GraalVM原生镜像

在本节中,我们将为一个Spring Boot应用程序构建一个GraalVM原生镜像。首先,需要安装GraalVM并设置JAVA_HOME环境变量。其次,创建一个带有Spring Web和GraalVM原生支持依赖的Spring Boot应用程序:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>3.1.4</version>
</dependency>

还需要添加以下插件以支持GraalVM原生镜像:

<build>
    <plugins>
        <plugin>
            <groupId>org.graalvm.buildtools</groupId>
            <artifactId>native-maven-plugin</artifactId>
            <version>0.9.27</version>
        </plugin>
    </plugins>
</build>

该应用程序包含一个REST Controller 示例:

@RestController
class HelloController {
	
    @GetMapping
    public String hello() {
	    return "Hello GraalVM";
    }
}

使用Maven命令构建原生可执行文件:

$mvn -Pnative native:compile

使用native-maven-plugin构建GraalVM原生镜像。由于GraalVM原生镜像编译器执行静态代码分析,与常规的Java应用程序编译相比,构建时间较长。

以下是GraalVM编译的输出示例:

========================================================================================================================
GraalVM Native Image: Generating 'springboot-graalvm-docker' (executable)...
========================================================================================================================
<strong>[1/8] Initializing... (42.7s @ 0.15GB)</strong>
Java version: 17.0.8+9-LTS, vendor version: Oracle GraalVM 17.0.8+9.1
Graal compiler: optimization level: 2, target machine: x86-64-v3, PGO: ML-inferred
C compiler: gcc (linux, x86_64, 11.3.0)
Garbage collector: Serial GC (max heap size: 80% of RAM)

// 省略不重要日志

<strong>[2/8] Performing analysis... [******] (234.6s @ 1.39GB)</strong>
15,543 (90.25%) of 17,222 types reachable
25,854 (67.59%) of 38,251 fields reachable
84,701 (65.21%) of 129,883 methods reachable
4,906 types, 258 fields, and 4,984 methods registered for reflection
64 types, 70 fields, and 55 methods registered for JNI access
4 native libraries: dl, pthread, rt, z
[3/8] Building universe... (14.7s @ 2.03GB)
[4/8] Parsing methods... [*******] (55.6s @ 2.05GB)
[5/8] Inlining methods... [***] (4.9s @ 2.01GB)
[6/8] Compiling methods... [**********
[6/8] Compiling methods... [*******************] (385.2s @ 3.02GB)
[7/8] Layouting methods... [****] (14.0s @ 2.00GB)
[8/8] Creating image... [*****] (30.7s @ 2.72GB)
48.81MB (58.93%) for code area: 48,318 compilation units
30.92MB (37.33%) for image heap: 398,288 objects and 175 resources
3.10MB ( 3.75%) for other data
82.83MB in total

// 省略不重要日志

Finished generating 'springboot-graalvm-docker' in 13m 7s.

// 省略不重要日志

在上述编译输出中需要关注一些关键点,如下:

  • 编译使用GraalVM的Java编译器来编译应用程序。
  • 编译器对类型、字段和方法进行可达性检查。
  • 然后编译构建原生可执行文件,并显示可执行文件的大小和编译所花费的时间。
  • 成功构建后,我们可以在目标目录中找到原生可执行文件。该可执行文件可以在命令行中执行。

构建Docker镜像

接下来为前一步生成的原生可执行文件开发一个Docker镜像。

创建一个Dockerfile:

FROM ubuntu:jammy
COPY target/springboot-graalvm-docker /springboot-graalvm-docker
CMD ["/springboot-graalvm-docker"]

接下来,使用如下命令构建Docker镜像:

$docker build -t springboot-graalvm-docker .

成功构建后,可以看到`springboot-graalvm-docker`的Docker镜像已经可以使用了:

$docker images | grep springboot-graalvm-docker

可以使用以下命令执行这个镜像:

$docker run -p 8080:8080 springboot-graalvm-docker

上述命令启动了容器,Spring Boot的启动日志如下:

// 省略不重要日志
***  INFO 1 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization <strong>completed in 14 ms</strong>
***  INFO 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
***  INFO 1 --- [           main] c.b.g.GraalvmDockerImageApplication      : Started GraalvmDockerImageApplication in 0.043 seconds (process running for 0.046)

应用程序在43毫秒内启动。我们可以访问REST端点:

$curl localhost:8080

输出如下:

Hello GraalVM
责任编辑:华轩 来源: 今日头条

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK