graalvm
This is the fifth part of a series on building a microservice in Quarkus. The other parts were:
Ť他是在Quarkus建设的microService一系列的五分之一。 其他部分是:
Part Three: Connecting to third party APIs and testing with Wiremock
In this part we are going to deploy the service running in GraalVM.
在这一部分中,我们将部署在GraalVM中运行的服务。
GraalVM (GraalVM)
GraalVM is a game-changing technology that has only been production ready since 2019. It is a Java VM that contains a JIT compiler and supports building of native images allowing AOT (Ahead Of Time) compilation of java applications. The executable file built by the native image does not run on a JVM but as a platform-specific native application. The binary image contains all of the necessary libraries and dependencies significantly reducing the startup and execution time.
GraalVM是一项改变游戏规则的技术,自2019年以来才投入生产。它是一种Java VM,其中包含JIT编译器并支持构建本机映像,从而允许对Java应用程序进行AOT(提前)编译。 由本机映像构建的可执行文件不在JVM上运行,而是作为特定于平台的本机应用程序运行。 二进制映像包含所有必需的库和依赖项,从而大大减少了启动和执行时间。
安装GraalVM (Installing GraalVM)
You can get instructions for downloading GraalVM for your OS of choice here .
您可以在此处获得有关为所选操作系统下载GraalVM的说明。
Next configure the runtime. Here is how you would do it for macOS
接下来配置运行时。 这是针对macOS的操作方法
export GRAALVM_HOME=/Library/Java/JavaVirtualMachines/graalvm-ce-java11-20.1.0/Contents/Home
For building native images you will need to install the native image tool
要构建本机映像,您将需要安装本机映像工具
$ {GRAALVM_HOME}/bin/gu install native-image
Once you have installed the native image tool you can create native image binaries using the tool
安装本机映像工具后,您可以使用该工具创建本机映像二进制文件
$ native-image my-app.jar
This creates a native binary in the current directory. You can now invoke the binary as follows:
这将在当前目录中创建一个本地二进制文件。 现在,您可以按以下方式调用二进制文件:
$ ./my-app
建立本机映像 (Building the Native Image)
You can follow along with the code by pulling the branch for this article
您可以通过拉动本文的分支来遵循代码
git clone git@github.com:iainporter/sms-service.git
cd sms-service
git checkout part_five
Up until now we have built the SMS microservice to run in a JVM. To run it as a native image we need to either pass an argument to maven on the command line:
到目前为止,我们已经构建了可以在JVM中运行的SMS微服务。 要将其作为本机映像运行,我们需要在命令行中将参数传递给maven:
mvn install -Dquarkus.package.type=native
Or we can add a profile and use the same argument which also allows us to run integration tests against the native image. Before we do that however let’s add a docker file to build a minimal image in which to run the native executable.
或者,我们可以添加一个配置文件并使用相同的参数,这也允许我们针对本机映像运行集成测试。 但是,在执行此操作之前,让我们添加一个docker文件来构建一个最小的映像,以在其中运行本机可执行文件。
FROM registry.access.redhat.com/ubi8/ubi-minimal:8.1
WORKDIR /deployments/
COPY --chown=1001:root target/*-runner /deployments/application
EXPOSE 8080
USER 1001
CMD ./application -Dquarkus.http.host=0.0.0.0
The profile in the pom
pom中的配置文件
<profile>
<id>native</id>
<activation>
<property>
<name>native</name>
</property>
</activation>
<build>
<plugins>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<version>3.0.0-M3</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
<configuration>
<systemPropertyVariables>
<native.image.path>
${project.build.directory}/${project.build.finalName}-runner
</native.image.path>
</systemPropertyVariables>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.6.0</version>
<executions>
<!-- Create new docker image -->
<execution>
<id>docker-build-service</id>
<phase>install</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>docker</executable>
<workingDirectory>${project.basedir}</workingDirectory>
<arguments>
<argument>build</argument>
<argument>-f</argument>
<!-- build the image with the native executable
use mvn install -Pnative to build-->
<argument>Dockerfile.native</argument>
<argument>-t</argument>
<argument>porterhead/sms-service</argument>
<argument>.</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<properties>
<quarkus.package.type>native</quarkus.package.type>
</properties>
</profile>
Now we can install the executable with the maven command
现在我们可以使用maven命令安装可执行文件
mvn clean install -Pnative
It is here that we run into trouble. In order to build the native executable the GraalVM compiler needs to run a static analysis of the code to perform ahead of time compilation. It has to make a closed world assumption about the code, meaning that all classes have to be available at compile time. No dynamic class loading at runtime or java agents such as JMX, and the use of reflection is limited. All of these limitations are what make the application fast to boot so compromises have to be made. Quarkus is built to run on GraalVM and is optimised for that purpose.
我们在这里遇到了麻烦。 为了构建本机可执行文件,GraalVM编译器需要对代码进行静态分析,以便提前进行编译。 它必须对代码做出封闭的假设,这意味着所有类都必须在编译时可用。 在运行时或JMX之类的Java代理中不会动态加载类,并且反射的使用受到限制。 所有这些限制是使应用程序快速启动的原因,因此必须做出妥协。 Quarkus可以在GraalVM上运行,并且为此目的进行了优化。
The SMS microservice makes use of the OKHttp client that falls over at compilation time:
SMS微服务利用在编译时掉落的OKHttp客户端:
Error: No instances of sun.security.provider.NativePRNG are allowed in the image heap as this class should be initialized at image runtime. To see how this object got instantiated use -H:+TraceClassInitialization.
Detailed message:
Trace: object java.security.SecureRandom
There are a bunch of properties that you can use to tweak the compiler behaviour but in this instance it gives us an opportunity to rip out the rest client and use the rest client in Quarkus which won’t have compilation issues.The Rest client interface can be found here and the implementation here. Once we have replaced the rest client the application compiles to a native executable.
您可以使用一堆属性来调整编译器的行为,但是在这种情况下,它为我们提供了机会,可以淘汰REST客户端并在Quarkus中使用REST客户端,而不会出现编译问题。发现这里和实施在这里 。 一旦我们替换了其余客户端,应用程序将编译为本地可执行文件。
内存占用空间和启动时间 (Memory Footprint and Boot Time)
Now that we can build the native application we can compare the memory size and startup time. The normal JVM image size is 559MB
现在我们可以构建本机应用程序,可以比较内存大小和启动时间了。 正常的JVM映像大小为559MB
![Image for post](https://i-blog.csdnimg.cn/blog_migrate/4f833e4098751dd37c2e616a6b32657f.png)
The startup time for the JVM image is over 15s
JVM映像的启动时间超过15秒
![Image for post](https://i-blog.csdnimg.cn/blog_migrate/ea94e8451a66d071105a36100ef64328.png)
The native image size is less than half of the JVM image
本机映像大小小于JVM映像的一半
![Image for post](https://i-blog.csdnimg.cn/blog_migrate/e4530a7371361063e17c233bcbde2fea.png)
The startup time is lightening fast. In fact it is so quick that is starts up before the postgres database is ready and so fails to start. To fix this we need to add a wait utility to the container
启动时间Swift缩短。 实际上,它是如此之快,以至于在postgres数据库准备就绪之前就已启动,因此无法启动。 要解决此问题,我们需要在容器中添加一个wait实用程序
ADD https://github.com/ufoscout/docker-compose-wait/releases/download/2.2.1/wait /wait
RUN chmod +x /wait
EXPOSE 8080
USER 1001
CMD /wait && ./application -Dquarkus.http.host=0.0.0.0
We make use of this in the docker-compose file
我们在docker-compose文件中使用它
environment:
WAIT_HOSTS: postgres-db:5432
The sms service will wait until postgres is available until starting up. When it does start up the result is less than 2 seconds.
短信服务将等到postgres可用后再启动。 当它启动时,结果不到2秒。
![Image for post](https://i-blog.csdnimg.cn/blog_migrate/c58ecfa76956033a00195fa178afb385.png)
This might seem like a long time but consider that the service has to connect to the database, run several flyway migrations, as well as set up the debezium connector to tail the database logs and set up kafka listeners. Compared to the JVM image it is incredibly fast.
这可能看起来很长一段时间,但考虑到该服务必须连接到数据库,运行多个迁移迁移,以及设置debezium连接器以尾随数据库日志并设置kafka侦听器。 与JVM映像相比,它的速度非常快。
The code for this whole series on building a production-ready microservice in Quarkus is available here.
有关在Quarkus中构建生产就绪的微服务的整个系列的代码,请参见此处 。
翻译自: https://medium.com/@changeant/running-a-microservice-in-quarkus-on-graalvm-52d6b42a5840
graalvm