应“云”而生的 Java 框架:构建本机可执行文件

===================

Spring 应用镜像使用 openjdk:11.0-jre-slim 作为 base 镜像,大小为 220MB。

docker images

REPOSITORY TAG IMAGE ID CREATED SIZE

spring/spring-getting-started latest 5f47030c5c3f 6 minutes ago 237MB

quarkus/quarkus-getting-started distroless2 fe973c5ac172 24 minutes ago 49MB

quarkus/quarkus-getting-started distroless 6fe27dd44e86 31 minutes ago 51MB

quarkus/quarkus-getting-started ubi 8f86f5915715 58 minutes ago 132MB

Java 应用容器化的困境

=============

云原生世界中,应用容器化是个显著的特点。Java 应用容器化时面临了如下问题:

  • 应用启动慢:其实这是 Java 应用的问题。Java 应用占用内存多;JVM 虚拟机启动时需要做环境的初始化、预加载大量的类、初始化线程等等。启动耗时视应用情况需要几秒,甚至可达分钟级。较长的启动耗时,也抑制了水平伸缩性。即使在 Serverless 这种响应耗时要求不高的场景,也会被嫌弃。

  • 镜像过大:其实使用了镜像的分层设计,常见的一个 SpringCloud 应用的 über-jar 包可能都有 7、80MB。

  • 空间占用:虽然用了镜像分层,但积少成多,也会增加存储成本。

Quarkus 与本机映像(native image)

===========================

Quarkus 的开发遵从了容器优先的原则:

  • 支持 Graal/SubstrateVM

  • 构建时处理元数据

  • 减少反射的使用

  • 本机映像预启动

本机映像是将 Java 代码提前编译为可执行文件(称为本机映像)的技术。该可执行文件包括应用程序类、其依赖项中的类、运行时间类以及 JDK 中的静态链接本机代码。它不是在 Java VM 上运行,而是包括必要的组件,例如内存管理,线程调度等,这些组件来自另一个运行时系统 “Substrate VM”。“Substrate VM” 是运行时组件(例如反优化器,垃圾收集器,线程调度等)的名称。与 JVM 相比,生成的程序具有更快的启动时间和更低的运行时内存开销。

如何构建本机映像

========

环境配置参考 上一篇文章 ,可以直接 从这里下载源码 。

配置 GraalVM

==========

之前我们使用了 sdkman 进行 GraalVM 安装。设置 GRAALVM_HOME 环境变量:

export GRAALVM_HOME=sdk home java 21.0.0.2.r11-grl

使用 gu 安装 native-image :

${GRAALVM_HOME}/bin/gu install native-image

构建本机可执行文件

=========

在源码的 pom.xml 中,我们可以看到如下的 profile :

native

<quarkus.package.type>native</quarkus.package.type>

我们使用这个 profile 进行本机可执行文件的构建,整个构建耗时 几分钟

./mvnw package -Pnative

部分构建日志:

[INFO] — maven-jar-plugin:2.4:jar (default-jar) @ quarkus-getting-started —

[INFO]

[INFO] — quarkus-maven-plugin:1.13.0.Final:build (default) @ quarkus-getting-started —

[INFO] [org.jboss.threads] JBoss Threads version 3.2.0.Final

[INFO] [io.quarkus.deployment.pkg.steps.JarResultBuildStep] Building native image source jar: /Users/addo/Workspaces/private_w/quarkus-getting-started/target/quarkus-getting-started-1.0.0-SNAPSHOT-native-image-source-jar/quarkus-getting-started-1.0.0-SNAPSHOT-runner.jar

[INFO] [io.quarkus.deployment.pkg.steps.NativeImageBuildStep] Building native image from /Users/addo/Workspaces/private_w/quarkus-getting-started/target/quarkus-getting-started-1.0.0-SNAPSHOT-native-image-source-jar/quarkus-getting-started-1.0.0-SNAPSHOT-runner.jar

[INFO] [io.quarkus.deployment.pkg.steps.NativeImageBuildContainerRunner] Using docker to run the native image builder

[INFO] [io.quarkus.deployment.pkg.steps.NativeImageBuildContainerRunner] Checking image status quay.io/quarkus/ubi-quarkus-native-image:21.0.0-java11

21.0.0-java11: Pulling from quarkus/ubi-quarkus-native-image

Digest: sha256:becf08de869e707beaa5e57444b533ef93ebef15aad90c92ac660ddf7cea2b11

Status: Image is up to date for quay.io/quarkus/ubi-quarkus-native-image:21.0.0-java11

quay.io/quarkus/ubi-quarkus-native-image:21.0.0-java11

[INFO] [io.quarkus.deployment.pkg.steps.NativeImageBuildStep] Running Quarkus native-image plugin on GraalVM Version 21.0.0 (Java Version 11.0.10+8-jvmci-21.0-b06)

[INFO] [io.quarkus.deployment.pkg.steps.NativeImageBuildRunner] docker run --env LANG=C --rm -v /Users/addo/Workspaces/private_w/quarkus-getting-started/target/quarkus-getting-started-1.0.0-SNAPSHOT-native-image-source-jar:/project:z quay.io/quarkus/ubi-quarkus-native-image:21.0.0-java11 -J-Dsun.nio.ch.maxUpdateArraySize=100 -J-Djava.util.logging.manager=org.jboss.logmanager.LogManager -J-Dvertx.logger-delegate-factory-class-name=io.quarkus.vertx.core.runtime.VertxLogDelegateFactory -J-Dvertx.disableDnsResolver=true -J-Dio.netty.leakDetection.level=DISABLED -J-Dio.netty.allocator.maxOrder=1 -J-Duser.language=en -J-Duser.country=CN -J-Dfile.encoding=UTF-8 --initialize-at-build-time= -H:InitialCollectionPolicy=com.oracle.svm.core.genscavenge.CollectionPolicy$BySpaceAndTime -H:+JNI -H:+AllowFoldMethods -jar quarkus-getting-started-1.0.0-SNAPSHOT-runner.jar -H:FallbackThreshold=0 -H:+ReportExceptionStackTraces -J-Xmx5g -H:-AddAllCharsets -H:EnableURLProtocols=http --no-server -H:-UseServiceLoaderFeature -H:+StackTrace quarkus-getting-started-1.0.0-SNAPSHOT-runner

[quarkus-getting-started-1.0.0-SNAPSHOT-runner:25] classlist: 5,859.24 ms, 0.96 GB

[quarkus-getting-started-1.0.0-SNAPSHOT-runner:25] (cap): 633.34 ms, 0.94 GB

[quarkus-getting-started-1.0.0-SNAPSHOT-runner:25] setup: 2,468.19 ms, 0.94 GB

00:06:00,437 INFO [org.jbo.threads] JBoss Threads version 3.2.0.Final

[quarkus-getting-started-1.0.0-SNAPSHOT-runner:25] (clinit): 516.65 ms, 2.23 GB

[quarkus-getting-started-1.0.0-SNAPSHOT-runner:25] (typeflow): 12,642.02 ms, 2.23 GB

[quarkus-getting-started-1.0.0-SNAPSHOT-runner:25] (objects): 11,340.37 ms, 2.23 GB

[quarkus-getting-started-1.0.0-SNAPSHOT-runner:25] (features): 525.87 ms, 2.23 GB

[quarkus-getting-started-1.0.0-SNAPSHOT-runner:25] analysis: 26,032.67 ms, 2.23 GB

[quarkus-getting-started-1.0.0-SNAPSHOT-runner:25] universe: 1,394.06 ms, 2.16 GB

[quarkus-getting-started-1.0.0-SNAPSHOT-runner:25] (parse): 2,690.38 ms, 2.16 GB

[quarkus-getting-started-1.0.0-SNAPSHOT-runner:25] (inline): 4,336.77 ms, 2.73 GB

[quarkus-getting-started-1.0.0-SNAPSHOT-runner:25] (compile): 17,580.03 ms, 2.71 GB

[quarkus-getting-started-1.0.0-SNAPSHOT-runner:25] compile: 26,152.06 ms, 2.71 GB

[quarkus-getting-started-1.0.0-SNAPSHOT-runner:25] image: 3,288.43 ms, 2.70 GB

[quarkus-getting-started-1.0.0-SNAPSHOT-runner:25] write: 1,904.64 ms, 2.70 GB

[quarkus-getting-started-1.0.0-SNAPSHOT-runner:25] [total]: 67,414.16 ms, 2.70 GB

[WARNING] [io.quarkus.deployment.pkg.steps.NativeImageBuildStep] objcopy executable not found in PATH. Debug symbols will not be separated from executable.

[WARNING] [io.quarkus.deployment.pkg.steps.NativeImageBuildStep] That will result in a larger native image with debug symbols embedded in it.

[INFO] [io.quarkus.deployment.QuarkusAugmentor] Quarkus augmentation completed in 74739ms

[INFO] ------------------------------------------------------------------------

[INFO] BUILD SUCCESS

[INFO] ------------------------------------------------------------------------

[INFO] Total time: 01:21 min

[INFO] Finished at: 2021-04-17T08:06:47+08:00

[INFO] ------------------------------------------------------------------------

假如构建时出现类似 Caused by: java.lang.RuntimeException: Image generation failed. Exit code was 137 which indicates an out of memory error. Consider increasing the Xmx value for native image generation by setting the “quarkus.native.native-image-xmx” property 这种报错。需要调整下 Docker 的设置,比如笔者使用的 macOS,打开 Docker Desktop > Preference > Resource > Advanced,将内存从默认的 2GB 调大,比如 8GB。

从构建日志可以看出,构建的过程是在 quay.io/quarkus/ubi-quarkus-native-image 的容器中完成的。虽然异常提示调整 “quarkus.native.native-image-xmx” ,其实是容器内存太小导致的。

构建成功后,可以在 target 中找到 quarkus-getting-started-1.0.0-SNAPSHOT-runner 。这是一个可执行文件,大小为 28MB。

尝试执行该文件,收到 zsh: exec format error: ./target/quarkus-getting-started-1.0.0-SNAPSHOT-runner 错误。因为这是一个 Linux 可执行文件,因此我们需要在容器中运行。

构建本机镜像

======

在源文件的 src/main/docker 目录中,我们可以找到 Dockerfile.native :

FROM registry.access.redhat.com/ubi8/ubi-minimal:8.3

WORKDIR /work/

RUN chown 1001 /work \

&& chmod “g+rwX” /work \

&& chown 1001:root /work

COPY --chown=1001:root target/*-runner /work/application

EXPOSE 8080

USER 1001

CMD [“./application”, “-Dquarkus.http.host=0.0.0.0”]

运行镜像

====

本地运行一下,可以看出启动只需要 0.013s 。

docker run --rm -p 8080:8080 quarkus/quarkus-getting-started:latest


–/ __ / / / / _ | / _ / //_/ / / / __/

-/ // / // / __ |/ , / ,< / // /\ \

–___// |//|//||_/_/

2021-04-17 00:22:27,146 INFO [io.quarkus] (main) quarkus-getting-started 1.0.0-SNAPSHOT native (powered by Quarkus 1.13.0.Final) started in 0.013s. Listening on: http://0.0.0.0:8080

2021-04-17 00:22:27,147 INFO [io.quarkus] (main) Profile prod activated.

2021-04-17 00:22:27,147 INFO [io.quarkus] (main) Installed features: [cdi, resteasy]

测试一下端点:
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

总结

总体来说,如果你想转行从事程序员的工作,Java开发一定可以作为你的第一选择。但是不管你选择什么编程语言,提升自己的硬件实力才是拿高薪的唯一手段。

如果你以这份学习路线来学习,你会有一个比较系统化的知识网络,也不至于把知识学习得很零散。我个人是完全不建议刚开始就看《Java编程思想》、《Java核心技术》这些书籍,看完你肯定会放弃学习。建议可以看一些视频来学习,当自己能上手再买这些书看又是非常有收获的事了。


《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
的工作,Java开发一定可以作为你的第一选择。但是不管你选择什么编程语言,提升自己的硬件实力才是拿高薪的唯一手段。

如果你以这份学习路线来学习,你会有一个比较系统化的知识网络,也不至于把知识学习得很零散。我个人是完全不建议刚开始就看《Java编程思想》、《Java核心技术》这些书籍,看完你肯定会放弃学习。建议可以看一些视频来学习,当自己能上手再买这些书看又是非常有收获的事了。

[外链图片转存中…(img-DQ52nEhr-1713671283004)]
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 7
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值