0x01 Spring Native介绍

众所周知Sping Boot的启动速度在15s左右,Serverlless架构下如果没有预留实例的情况下,遇到业务峰时候会出现一部分终端用户服务长时间得不到响应甚至出现不可用情况。对用户体验敏感的应用及其不适合。如果大量预留实例会极大增加服务器成本造成浪费,如果采用人工值守的方式又是一种及其落后的运维方式,复杂业务场景下对运维人员也是一种折磨。那有没有一种方式能加快Spring Boot
的启用速度呢?答案是:有!

这个神器就是Spring官方提供的工具:Spring Native。 Spring Native使用GraalVM提供的编译器将Spring应用直接编译成“Native Image"形式能单独运行并且包含共享库的二进制程序。直接抛弃了JVM,和JVM相比Native Image 简单易用并且足以支撑各种业务场景,包括:微服务、函数计算、更友好的容器支持和k8s。使用Native Image一个最明显的优势是加快启动速度、瞬间触达性能峰值和降低内存占用。

但是Native Image也有一些问题和缺点需要时间来解决,相比传统应用编译Native Image 是一个很重的过程,并且缺少运行时优化,相比JVM还不够成熟。

和JVM相比其主要特点如下:

  • 构建时从入口开始静态分析
  • 未使用部分不会构建
  • 反射、资源和动态代理需要自行配置
  • 类路径在构建阶段固定
  • 没有懒加载:启动时在执行阶段需要的东西都被提前加载到内存
  • 部分代码在构建时运行
  • 并非支持所有Java项目,有一些限制

Spring Native的目的是提供一个除JVM的的另外一个选择,Spring Native 部署提供一个轻量级的容器。事实上在这个平台上Spring 应用几乎不用做修改就可以很好的运行。

Spring Native包含的模块:

  • Spring-native 运行时核心依赖,也提供了Native API接口
  • spring-native-configuration: 配置
  • spring-native-docs: 文档
  • spring-native-tools: 构建工具
  • spring-aot: AOT转换工具核心
  • spring-aot-gradle-plugin: gradle AOT转换插件
  • spring-aot-maven-plugin: maven AOT转换插件
  • samples: 特性样例

说了这么多优点还有一个最重要的没说: Spring Native仍然是Beta阶段(2021/08/02),处于快速开发期,可能会引入很多巨大的变更。因此目前不建议直接使用在实际项目中。

0x02 使用容器方式构建应用

安装Docker

使用下面的的实例来构建服务,代码克隆到本地。Spring Native 0.10.2只支持Spring boot2.5.3,如果有必要自己修改下版本

git clone https://github.com/spring-guides/gs-rest-service
cd gs-rest-service/complete

Maven依赖

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.5.3</version>
    <relativePath/>
</parent>

添加Spring Native依赖
org.springframework.experimental:spring-native 提供

<dependencies>
    <!-- ... -->
    <dependency>
        <groupId>org.springframework.experimental</groupId>
        <artifactId>spring-native</artifactId>
        <version>0.10.2</version>
    </dependency>
</dependencies>

添加SPring AOT插件

<build>
    <plugins>
        <!-- ... -->
        <plugin>
            <groupId>org.springframework.experimental</groupId>
            <artifactId>spring-aot-maven-plugin</artifactId>
            <version>0.10.2</version>
            <executions>
                <execution>
                    <id>test-generate</id>
                    <goals>
                        <goal>test-generate</goal>
                    </goals>
                </execution>
                <execution>
                    <id>generate</id>
                    <goals>
                        <goal>generate</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

启用Native Image支持

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <configuration>
        <image>
            <builder>paketobuildpacks/builder:tiny</builder>
            <env>
                <BP_NATIVE_IMAGE>true</BP_NATIVE_IMAGE>
            </env>
        </image>
    </configuration>
</plugin>

GraalVM version版本随着Buildpacks自动升级,如果想指定版本需要想下面这样操作:

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <configuration>
        <!-- ... -->
        <image>
            <buildpacks>
                <buildpack>gcr.io/paketo-buildpacks/java-native-image:5.3.0</buildpack>
            </buildpacks>
        </image>
    </configuration>
</plugin>

添加Maven仓库

<repositories>
    <!-- ... -->
    <repository>
        <id>spring-release</id>
        <name>Spring release</name>
        <url>https://repo.spring.io/release</url>
    </repository>
</repositories>

增加Maven插件仓

<pluginRepositories>
   <pluginRepository>
      <id>spring-release</id>
      <name>Spring release</name>
      <url>https://repo.spring.io/release</url>
   </pluginRepository>
</pluginRepositories>

构建应用

$ mvn spring-boot:build-image

运行应用

$ docker run --rm -p 8080:8080 rest-service:0.0.1-SNAPSHOT

也可以使用docker-compose方式

version: '3.1'
services:
  rest-service:
    image: rest-service:0.0.1-SNAPSHOT
    ports:
      - "8080:8080"

docker composer启动

$ docker-compose up

测试应用:
访问如下地址: http://localhost:8080/greeting 将会看到 {"id":1,"content":"Hello, World!"}

0x03总结

虽然Spring Native仍然处于 Beta阶段,但是我们已经感受到其简便方式的解决了函数计算和一些微服务场景下Java应用的痛点,未来不可限量。

Tags: spring, serverless

Related Posts:

Leave a Comment