Blog chevron_right 未分类

您的 JVM 和 JIT 编译可以减少云浪费

Azul 云成本优化专家研究了公司在云成本方面面临挑战的原因。经过仔细调查,他们发现了六个错误但广为流传的 Java 云成本优化谬见,并对此分别提出了事实反驳。 

谬见:所有 Java 运行时都是相同的。 

现实:行业分析师和运行现代云架构的领先公司一致认为,使用具有 JIT 编译功能的高性能 Java 运行时可以提高 Java 应用程序的性能,并减少云浪费。 

这是一种常见误解,会让您和团队付出数百万美元的代价。

Java 仍然是构建网站、移动应用程序和分布式数据处理框架等的最热门语言之一(来源:《Java 如今是否仍有实用价值?》Jetbrains,2024 年 7 月),而这一切正是广告科技、金融科技、游戏、电子商务、高性能交易,以及在线旅行与预订行业所必需的。Azul 的 2023 年《Java 现状调查与报告》还显示,Java 在商业企业中几乎得到普遍采用。

而数字业务是在云端运行的。明白我们的意思吗? 

可以说,您很可能只关注您使用的 Java 框架,或您正在使用的版本。您会花费时间思考功能的迭代速度以及如何以最快的速度进入市场,同时提供最佳客户体验。  或者,也许您还希望在提供最佳客户体验的同时,将 Java 资产的拥有成本维持在较低水平

Java Cloud Cost Optimization Myths - Your choice of JVM and JIT compilation can help reduce cloud waste

Java 就是 Java,不是这样吗?并非如此。

您是否曾经停下来思考过,您使用的是什么 Java 虚拟机?  并非所有 Java 运行时都是相同的。虽然大多数 Java 发行版只是 OpenJDK 的标准副本(包括 Oracle、Temurin 和 Amazon Corretto 的发行版),只对 OpenJDK 进行了普通封装。 

然而,一些 JVM 提供了巨大优势。您对 JVM 的选择至关重要。一些 JVM 经过设计,可增强 Java 工作负载,使其运行更快、部署更容易、使用的计算资源更少。 

我们发现,Java 的运行速度越快,其使用的计算资源就越少,从而有助于减少云浪费现象的产生。您知道吗?  有一种高性能的 Java 运行时,它经过专门优化,可通过加快代码运行速度来提高应用程序性能,同时减少云浪费。 

让我们深入地探讨这个问题

如今,为了应对峰值负载,大多数应用程序通常会进行过度预配置。但是,为什么要支付所有这些资本支出来预配置足以应对峰值负载的硬件,然后再花费运营成本来为这些机器供电、散热和维护?不如让 Amazon、Microsoft 或 Google 等公司为您处理这些事务,您只需像支付电费一样,支付使用费用。 

这就是云计算的承诺:通过基于效用的定价模式,以较低的成本运行任务关键型企业应用程序。 

遗憾的是,现实中的结果往往有所不同,人们发现,迁移到云端的成本比本地托管更高。为什么会这样,我们又该如何解决? 

让我们来专门看看使用 Java 编写的 JVM 应用程序。许多其他语言编写的代码,如 KotlinScalaClojure,经过编译,也可以在 JVM 上运行。 

微服务为架构基于云的应用程序提供了现代化的方法。比起开发单一的单体应用程序,我们可以将应用程序拆分成能够松散耦合但又高度内聚的分散服务。这样一来,当一项服务成为性能瓶颈时,我们可以启动该服务的新实例,均衡使用负载,消除瓶颈,而无需更改系统的其他部分。 

在这里,JVM 的一项核心功能可能导致云资源的浪费。 

为了兑现“一次编写,随处运行”的承诺Java 应用程序会编译字节码即针对虚拟机(而非特定处理器)的指令。当 Java 应用程序启动时,JVM 会对其进行分析,找出可编译为原生代码的常用代码热点。这种即时 (JIT) 编译可提供出色的性能,因为 JVM 可以准确地知道代码将如何使用,并据此进行优化。 

然而,识别和编译所有常用代码段所需的时间可能比预期更长,这实际上是一个较复杂的多阶段过程。对于 Web 或应用程序服务器等长时间运行的进程来说,这种预热时间通常不是问题。而微服务可能会频繁地启动和停止,以便动态响应负载变化。在微服务提供全部承载能力之前,等待其完成预热将降低这种方法的优势。 

常用的解决方案是启动服务的多个实例,并让它们保持运行,以便在需要时立即提供完整性能。这显然非常浪费,而且会产生不必要的云基础设施成本。

Cloud waste chart: Java-based application speed by optimization level

如何通过 AOT 或 JIT 编译解决这个问题?

一种方法是使用提前编译 (AOT)。与 JIT 编译不同,这种方法将所有代码直接编译为原生指令。这完全消除了预热,使应用程序从一开始就能达到完整的性能级别。 

尽管这听起来像是理想的解决方案,但也具有成本和局限性。 

AOT 在编译代码时不知道代码将被如何使用,这限制了优化的可能性。JIT 编译具有分析信息,可以根据应用程序的使用方式进行定制的精确优化。通常,这会带来显著的整体性能提升。 

对于短暂的微服务,即所谓的“无服务器计算”,AOT 提供了明显的优势。对于任何至少运行几分钟的服务,JIT 将带来更好的性能,从而降低云计算成本。

AOT 编译 JIT 编译
类加载阻止了方法内联 可以使用积极的方法内联
无运行时字节码生成 可以使用运行时字节码生成
反射很复杂 反射(相对)简单
无法使用推测性优化 可以使用推测性优化
总体性能通常较低 总体性能通常较高
从一开始就全速运行 需要预热时间
没有运行时编译代码的 CPU 开销 有运行时编译代码的 CPU 开销
AOT 编译和 JIT 编译都是执行 Java 代码的好方法。
但是,尽管 AOT 在启动方面具有一系列优势,但 JIT 编译器通常能提供在运行时性能更优的代码。

另一种解决方案是 ReadyNow 预热技术,它是 Platform Prime 高性能 Java 运行时的一部分。 

如我们所见,问题在于每次启动微服务实例时,JVM 都必须执行相同的分析,以识别热点、收集分析信息,并将它们编译为原生代码。即使我们之前曾多次以同样的方式使用该微服务,情况也是如此。使用 ReadyNow,服务在生产环境中启动后可以使用实际请求(而非模拟请求)进行预热。当服务完全预热(达到最佳性能水平)后,将收集一个配置文件。此配置文件包含获得该性能水平所需的以下所有信息:热点列表、分析数据,甚至已编译的代码。

Cloud waste chart: latency over time in Java-based applications with and without the ReadyNow JIT compiler

当服务需要再次启动时,配置文件将作为执行参数的一部分提供。该配置文件可确保当 JVM 准备好处理第一个事务时,性能几乎达到采集配置文件时的水平。 

ReadyNow 几乎消除了所有预热时间,同时保留了 JIT 编译的所有性能优势。该系统提供了完整的灵活性,因为可以根据服务使用的时间和场合,对同一服务使用不同的配置文件。例如,周一早上的工作负载配置文件可能与周五下午有很大不同。ReadyNow 可以存储多个配置文件,并在需要时选择合适的配置文件。 

由于基于 JVM 的微服务预热时间极短,因此无需在后台维护闲置的服务池。这可以显著减少云浪费。 

经过性能优化的 JVM 还包括一个替代的内存管理系统,消除了典型的事务延迟。JIT 编译系统也得到了改进,可以提供更高的吞吐量。这些措施并不是减少云浪费,而是简单地减少了提供相同承载能力所需的云资源。其效果是进一步降低云成本。 

使用 JTI 编译的高性能 Java 可减少云浪费

让我们来看一个真实客户的例子。Supercell 公司运营着全球最大的一些多人在线游戏。在最近发布的《荒野乱斗》中,因为 JVM 正在编译所需的代码,所以在启动新服务器时出现了延迟。通过切换到 Azul Platform Prime 并利用 ReadyNow,该公司能够提供更稳定的负载能力,减少游戏延迟,并将相同工作负载的 CPU 使用率降低 20% 到 25%。 

您认为您的代码可以运行得多快?  请查看我们最近的博客(链接),其中针对 OpenJDK 8、11、17 和 21,对高性能 Java 运行时进行了基准测试。您觉得比较结果如何? 

显然,运行代码速度更快的 JVM,需要的云资源也更少,这让您可以更好地利用已经承诺的、打折的云资源开支,甚至降低您的云账单费用!