写点什么

快速实现不打折扣的云原生 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:0010783

评论 1 条评论

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

《使用Gin框架构建分布式应用》阅读笔记:p101-p107

codists

Go gin框架 编程人

如何在2024选择8款项目进度跟踪系统

爱吃小舅的鱼

项目进度跟踪系统

Pencils Protocol 用户特权:DAPP持有者将长期获得生态空投

大瞿科技

哪些项目管理工具最实用?10款推荐清单

爱吃小舅的鱼

项目管理工具

什么是边缘计算?边缘计算技术的优势与挑战

3DCAT实时渲染

实时渲染 边缘计算平台 边缘计算技术

centos编译安装的php多版本切换

百度搜索:蓝易云

Lightroom Classic 2025(LRC2025)直装版

你的猪会飞吗

lrc2025下载 Lightroom Classic 2025

Pencils Protocol 用户福利,DAPP持有者将获 Scroll 生态空投

股市老人

Pencils Protocol 用户福利,DAPP持有者将获 Scroll 生态空投

BlockChain先知

Arm架构Ubuntu使用Docker安装Gitlab并使用

百度搜索:蓝易云

特斯拉自动驾驶出租车计划变成泡影?联想与Meta合作,推出面向PC的个人AI智能体AI Now|AI日报

可信AI进展

Bitmap 和 布隆过滤器傻傻分不清?你这不应该啊

程序员小富

Java redis 面试 布隆过滤器

MathType导数符号怎么打 MathType导数头上一点怎么打

阿拉灯神丁

数学 教程分享 MathType 导数 公式函数

Mybatis的<where>,<if>等标签用法

百度搜索:蓝易云

项目延期频发怎么办?试试这8款工具

爱吃小舅的鱼

项目排期进度软件

Pencils Protocol 用户特权:DAPP持有者将长期获得生态空投

加密眼界

淘系商品详情数据接口全解析:探索Taobao API的无限可能

代码忍者

pinduoduo API API 性能测试

Mac下的压缩包和Win看到的不一样怎么办 Mac压缩后Win电脑看文件名会乱码

阿拉灯神丁

#Mac 苹果电脑 解压缩工具 压缩软件 BetterZip 5

AI手机的启明星:从分级标准到智能体手机

脑极体

AI

硬盘分区数据恢复软件哪个好 硬盘分区数据如何恢复正常

阿拉灯神丁

EasyRecovery 电脑文件 数据恢复软件 硬盘数据恢复 软件包

CleanMyMac最新版本发布,全新界面与功能引领Mac优化潮流

阿拉灯神丁

#Mac 软件包 CleanMyMac X 清理软件 苹果电脑使用

Pencils Protocol 用户特权?持有 DAPP 将获 Scroll 生态空投!

石头财经

CrossOver软件安装成功,但找不到为什么 crossover安装后找不到应用程序

阿拉灯神丁

容器 #Mac CrossOver Mac下载 苹果电脑使用 CrossOver 24

提升项目管理效率?9款软件帮你实现

爱吃小舅的鱼

项目进度软件

若依vue前端 报错error:0308010C:digital envelope routines::unsupported

百度搜索:蓝易云

linux三剑客之awk命令详解

百度搜索:蓝易云

爱旭N型ABC组件闪耀粤水电集采,领跑集中式光伏新篇章

Geek_2d6073

如何挑选适合企业的项目进度工具?9款推荐

爱吃小舅的鱼

项目进度系统

LCD、LED、OLED显示技术发展对比

Dylan

技术 科技 LED OLED lcd

PAI 大语言模型评测平台现已支持裁判员模型评测

阿里云大数据AI技术

人工智能 大语言模型 PAI 模型评测

施工项目进度管理系统怎么选?9款工具评测

爱吃小舅的鱼

施工项目进度管理系统

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