写点什么

快速实现不打折扣的云原生 Java 应用

作者:Tobi Ajila, Thomas Watson

  • 2023-06-02
    北京
  • 本文字数:4694 字

    阅读完需:约 15 分钟

快速实现不打折扣的云原生Java应用

近年来,向云原生计算迁移一直是开发人员比较关注的事情,按照云原生方式他们的业务应用能够从减少 IT 基础设施,提高可扩展性等方面受益。当涉及到云端部署应用程序时,“伸缩至零(scale-to-zero)”是标准的供应(provisioning)策略,以便于在业务需求较低的时候降低成本。随着需求的增加,会供应更多的应用程序实例和运行时,这种扩展必须非常迅速,这样终端用户才不会遇到响应滞后的问题。运行时的启动时间会对扩展性能产生很大的影响。

 

Open Liberty是一个云原生 Java 运行时,与其他 Java 运行时类似,它是建立在 JVM 技术之上的。JVM(更广泛地说,整个 JDK)所提供的性能、调试能力和类库使其成为支撑应用程序的重要技术。尽管 JVM 以出色的吞吐能力而闻名,但是其启动时间却落后于 Go 和 C++等静态编译语言。考虑到伸缩至零的需求,所以多年以来,显著改善启动时间一直是所有 JVM 实现的关键创新领域。AppCDS(HotSpot)Shared Classes Cache(Eclipse OpenJ9)这样的元数据缓存技术在启动时间方面做出了令人瞩目的改进,但并没有在启动时间方面实现数量级级别的减少,而这恰好是 serverless 计算的扩展场景所需要的。

 

编译为原生镜像以减少启动时间

 

Graal Native Image曾经宣布,借助编译为原生的方式,它能够实现低于 100 毫秒的启动时间,因此得到很多的关注。这是 JVM 领域的一个重大转变,因为这是 Java 第一次在启动时间方面能够与 C++相抗衡。虽然 Graal Native Image 显著降低了启动时间,但这也是有一定代价的。

 

首先,静态编译要求在构建时对应用有一个全局的了解。对于开发人员来说,他们在构建应用时一直依赖的动态能力将会受到限制。比如,像反射、动态类加载和 invokedynamic 等操作均需要特殊处理,因为它们会干扰生成原生镜像时的静态分析。这意味着,我们可能需要对应用程序进行大量的修改,这样原生镜像才能够正常运行,更糟糕的是,应用程序的依赖可能也需要更新。

其次,调试会变得更具挑战性,因为我们此时调试的已经不是一个 JVM 应用,而是一个原生可执行文件。我们需要将熟悉的 Java 调试器替换为原生调试器(如gdb)来调查问题。有种解决方式是在开发环境中使用 JVM,在生产环境中使用原生镜像。但是,这意味着生产环境与开发环境是不一致的,最终我们可能必须要在两个不同的运行时中修复缺陷!

 

最后,JVM 提供的优秀的特性之一就是出色的吞吐量,即时(just-in-time)编译器能够在运行时根据实时数据优化应用程序以达到最佳性能。这一点也必须在原生镜像中牺牲掉,因为开发人员只有一次编译的机会,那就是在构建时。有些框架,比如Spring Native,已经建立了帮助 Java 开发人员在原生镜像约束下运行应用程序的能力,但不得不承认的是,开发人员必须放弃一些东西以获取原生镜像在启动时间方面的收益。

 

使用检查点/恢复功能跳过启动时间

 

Liberty 运行时采用了一种不同的方式来改善启动时间。Liberty 的目标是提供快速启动,而不必进行取舍,这是通过一项名为Liberty InstantOn的特性实现的。该特性提供了 Java 开发人员熟悉的所有功能,相对于没有使用 InstantOn 的 JVM 运行环境,它的运行时启动时间最多能够优化 10 倍。

 

从基础上来讲,Liberty InstantOn 是基于检查点/恢复(checkpoint/restore)技术的。我们启动一个应用程序,然后暂停它,并在某些明确定义的点上持久化应用程序的状态,这就是检查点。这个检查点就会成为应用镜像,当部署应用的时候,我们只需要从已保存的状态恢复镜像即可,这就是恢复,通过这种方式,应用程序就跳过了它通常要经历的启动和初始化过程(因为这些步骤已经运行过了)。

 

Liberty 使用了OpenJ9 CRIU提供的支撑功能,这是一项基于Linux CRIU的技术,它能够让任意应用均支持检查点和恢复。在 Liberty InstantOn 方式中,因为我们依然在 JVM 上运行,所以在吞吐量性能方面没有任何损失。Java 调试也能按照预期方式运行,所有依赖动态 JVM 能力的库也能正常运行。

 

解决检查点/恢复机制的局限性

 

尽管检查点/恢复的概念听起来很简单,但在现实中,会有一些限制(这是CRIU的运行方式所导致的)需要由运行时和 JVM 共同来解决,以便于让应用程序体验到这些收益。当执行检查点时(此时会构建镜像),CRIU 会将环境“冻结”在检查点状态中,包括环境变量、计算资源的信息(CPU、内存)以及时间本身的信息都会打包到镜像中。这些东西中的任何一项在恢复环境中都可能是不同的,从而导致应用程序的不一致,这是很难追踪的。此外,检查点可能会捕获一些数据,如果镜像要通过容器注册中心跨公共网络传输到部署环境中,这就不是很理想了。这些数据可能包含对端点的外部连接,而这些连接在恢复环境中可能并不存在,另外数据中还可能包含我们不想在检查点镜像中嵌入的安全令牌。

 

基于这些原因,OpenJ9 CRIU 支持内置的补偿机制,以确保在检查点保存的应用在恢复时的行为是正确和安全的。对时间敏感的 API 进行了修改以补偿检查点和恢复时的停机时间。对于像SecureRandom这样的随机 API 在恢复的时候对种子进行了重置(re-seed),以确保每次检查点恢复时,它都会被恢复为唯一的实例。

 

JVM 可以解决它所知道的所有事情,但是应用程序代码可能也需要类似的处理。Liberty 运行时通过与 JVM 合作来解决 JVM 无法自行处理的剩余问题,从而帮助开发人员摆脱检查点/恢复的复杂性。为了实现这一点,OpenJ9提供了一个钩子机制,开发人员可以利用它来注册在检查点之前和之后要执行的方法。这种机制被 Liberty 广泛采用,比如,在部署时重新解析配置,以确保为环境使用正确的配置。

 

所以,尽管 OpenJ9 提供了高效利用检查点/恢复技术的工具,但是增强现有应用程序启动时间的最简单的方式是在 Liberty 上使用 Liberty InstantOn 来运行它。Liberty InstantOn 对检查点/恢复过程进行了抽象,将开发人员的选择简化为只有几项,比如确定检查点用于应用程序启动之前还是之后。

 

总而言之,我们的终极目标是改善 Java 应用程序的云原生体验,这意味着无论采用什么样的技术,都必须要在云环境中高效运行。Liberty InstantOn 与容器技术(如 Docker 和Podman)实现了无缝集成。Liberty InstantOn 还能与KnativeOpenShift等容器引擎协作。我们完成了相关的工作以确保 Liberty InstantOn 能够在非特权模式下运行,因为这对生产环境的安全性是非常重要的。这项工作的成果正在回馈给 CRIU 项目。

 

使用自己的项目尝试一下 Liberty InstantOn

 

Liberty InstantOn 的 beta 版本已经公开可用,开发人员可以使用现有的应用程序进行尝试,以观察启动时间的改进(最多能够快 10 倍)。你只需要使用 Liberty InstantOn 工具为你的应用程序创建一个应用容器镜像即可。Open Liberty 发布了生产就绪的容器镜像,使你的应用程序可以很容易地进行容器化,以便于在容器引擎中运行,比如 Docker、Podman 或 Red Hat OpenShift 这样的 Kubernetes 环境。

 

Open Liberty 容器镜像包含了所有必要的依赖,以便于在 Open Liberty 运行时中运行应用程序。如下针对开发人员的指南描述了如何基于 Open Liberty beta-instanton 镜像(icr.io/appcafe/open-liberty:beta-instanton)创建一个带有应用程序的基础应用容器镜像,然后如何在此基础之上创建并添加一个包含检查点进程状态的层。beta-instanton 镜像包含了对 Open Liberty 创建检查点并将检查点进程存储到容器镜像层中所需的所有先决条件。这包括对 OpenJ9 CRIU 和 Linux CRIU 支持的早期访问构建。

 

如何使用 Liberty InstantOn 容器化应用程序,使其能够更快启动

如下的指南使用 Podman 来构建和运行容器,并且使用了Open Liberty入门指南中的应用程序。如果你手头有自己的应用程序,可以将其替换掉。

 

入门应用程序包含了一个Dockerfile,如下所示:

 

FROM icr.io/appcafe/open-liberty:full-java11-openj9-ubi

ARG VERSION=1.0ARG REVISION=SNAPSHOT

COPY --chown=1001:0 src/main/liberty/config/ /config/COPY --chown=1001:0 target/*.war /config/apps/

RUN configure.sh
复制代码

 

首先,开发人员需要更新 FROM 指令以使用 beta-instanton 镜像:

 

FROM icr.io/appcafe/open-liberty:beta-instanton
复制代码

 

然后,借助更新后的 Dockerfile,可以使用如下的命令构建应用容器镜像:

 

podman build –t getting-started .
复制代码

 

该命令会创建应用容器镜像,但是还没有创建检查点进程。应用程序的检查点进程是通过如下命令运行应用容器镜像来创建的,这里添加了一些额外的选项:

 

podman run \--name getting-started-checkpoint-container \--privileged \--env WLP_CHECKPOINT=applications \getting-started
复制代码

 

通过 WLP_CHECKPOINT 变量,Open Liberty 运行时声明在被配置的应用启动后但在打开端口以接受传入的请求之前对应用进程生成检查点。当应用程序进程完成检查点生成后,运行中的容器将会停止。这将会形成一个包含检查点进程状态的已停止的容器。

 

最后一步是将这个检查点进程状态以层的形式添加到原始应用程序的进程镜像中。这可以通过如下的命令将名为 getting-started-checkpoint-container 的已停止应用容器提交给一个新的容器镜像:

 

podman commit \getting-started-checkpoint-container \getting-started-instanton
复制代码

 

最终的结果是可运行的 getting-started-instanton 容器镜像。

 

运行具有 Linux 特权能力的容器

当运行 getting-started-instanton 容器时,开发人员必须授予其一组Linux能力,以便容器镜像中的 CRIU 二进制文件执行恢复过程:

 

  • cap_checkpoint_restore

  • cap_net_admin

  • cap_sys_ptrace

 

在创建检查点进程时,使用了一个具有特权的容器,它授予了容器镜像中的 CRIU 二进制文件所需的Linux能力

 

请通过如下的 Podman 命令以运行具有三种所需能力的容器:

podman run \--rm \--cap-add=CHECKPOINT_RESTORE \--cap-add=NET_ADMIN \--cap-add=SYS_PTRACE \-p 9080:9080 \getting-started-instanton
复制代码

 

getting-started-instanton 容器会以必要的权限来运行,以执行恢复过程,应用程序的运行速度要比原始的 getting-started 应用程序快 10 倍。

 

未来的改进

 

Open Liberty的beta版本发布了对 Liberty InstantOn 的定期更新。未来的版本已经规划了一些改进,它们将会让 Liberty InstantOn 构建和运行应用镜像变得更加容易。例如,为了消除对 NET_ADMIN Linux能力的要求,一些额外的相关工作已经完成。还有一项计划是在恢复应用的过程中移除对 SYS_PTRACE 能力的要求。这将减少运行应用所需的能力清单,在运行应用程序的时候,仅需 CHECKPOINT_RESTORE 能力即可。

 

其他规划包括在应用容器的构建步骤中执行应用进程检查点,这样不需要容器运行和容器提交命令就能将应用进程状态存储到应用容器镜像层中了。

 

请反馈你们的想法

 

虽然云原生需要对组织的业务方式做出许多变化,但是有了 Liberty InstantOn,开发人员就不用担心改变他们的应用开发方式了。

 

我们鼓励开发人员使用 Open Liberty 22.0.0.11-beta 或后续版本来尝试Liberty InstantOn的beta功能。欢迎通过项目的邮件列表进行反馈。如果遇到问题,开发人员可以在StackOverflow上发布问题。如果发现缺陷的话,欢迎提交issue

 

背景说明

 

Open LibertyEclipse OpenJ9均是开源项目。IBM 基于这些项目构建了其商业的WebSphere Liberty Java 运行时和IBM Semeru Runtimes Java 发行版。Liberty InstantOn 使用了 Linux Checkpoint/Restore In Userspace(CRIU)项目提供的检查点/恢复技术,并与 CRIU 合作,将代码反馈给该项目。

 

原文链接:


https://www.infoq.com/articles/rapid-startup-of-your-cloud-native-java/

 

相关阅读:


Java 是如何毁掉你的编程思维的?

系统学 Java,看这篇 Java 综合笔记万字总结就够了!..

Java 8 之后的新特性都是鸡肋吗?

扫盲篇:Java 中为啥一个 main 方法就能启动项目?

2023-06-02 11:0011514

评论 1 条评论

发布
用户头像
这种native程序应该是像Rust那样内存安全的吧?
2023-06-03 23:35 · 湖南
回复
没有更多了
发现更多内容

【spring-kafka】@KafkaListener详解与使用

石臻臻的杂货铺

kafka 11月月更

用python写一个时钟模型

乔乔

11月月更

什么是区块链Dapp智能合约系统开发?

W13902449729

区块链 dapp开发

实践竞争力第一!洞见科技获评艾瑞咨询隐私计算金融市场「综合领导者」

洞见科技

阿里云研究员马涛:龙蜥社区做对了两件事

云布道师

开源 云栖大会 龙蜥社区

【C语言】else 语句

謓泽

11月月更

阿里CTO程立:首个全面深度用云的天猫双11,更敏捷、更经济、更绿色

阿里技术

云计算 severless

Vue插件(plugin)

Augus

vue.js 11月月更

Apache Doris 1.1.4 版本正式发布!

SelectDB

数据库 大数据 数据仓库 Doris LTS

区块链基础知识介绍及dapp简单介绍

W13902449729

区块链 dapp

洞见科技中标浙江农商联合银行「隐私计算平台」项目

洞见科技

专访吴静涛丨从未有人把金融信创挑战说的这么透彻!

通明湖

洞见科技中标安康市数据要素流通平台(隐私计算平台)建设项目

洞见科技

现代API的类型划分

阿泽🧸

API 11月月更

昇腾AI异构计算架构CANN 6.0全新开放升级,全面释放AI生产力

极客天地

AI音乐创作,让每一个人都成为音乐家

叶落便知秋

应用发布新版本如何保障流量无损

阿里巴巴云原生

阿里云 微服务 云原生

KUMU×微帧科技,为菲律宾独角兽提供编码API服务

微帧Visionular

几分钟实现对恶意IP地址进行拦截,腾讯云Web防火墙实在太香了!

wljslmz

腾讯云 Web应用防火墙 黑名单 11月月更

一篇文章彻底理解数据库的各种超时参数

明哥的IT随笔

数据库 JDBC

创建一个科学决策必备的A/B实验,都需要哪些准备?——火山引擎 DataTester 使用指南

字节跳动数据平台

大数据 A/B测试

科普|什么是元宇宙

NFT Research

区块链 NFT 元宇宙

泛型由入门到精通

好程序员IT教育

EventBridge助力阿里云视觉智能开放平台AI智能存储实践

Apache RocketMQ

AI 消息队列 EventBridge

数据报告 | 2022年双十一变化趋势分析报告

前嗅大数据

双十一 数据报告 电商报告

数据中心的能源之翼:华为数据中心能源与伙伴共同飞翔

脑极体

网址访问速度免费加速教程:又拍云cdn

程序员余白

网页加速 CDN加速 11月月更

RocketMQ 在物流行业的应用与运维

Apache RocketMQ

RocketMQ 消息队列 Apache RocketMQ

模块五-作业

Weldon

架构实战营

Java Web(四)JS

浅辄

javaWeb JavaScrip 11月月更

数据分析的步骤

穿过生命散发芬芳

数据分析 11月月更

快速实现不打折扣的云原生Java应用_服务革新_InfoQ精选文章