Azul 云成本优化专家研究了公司在云成本方面面临挑战的原因。经过仔细调查,他们发现了六个错误但广为流传的 Java 云成本优化谬见,并对此分别提出了事实反驳。
谬见:所有 Java 运行时都是相同的。
现实:行业分析师和运行现代云架构的领先公司一致认为,使用具有 JIT 编译功能的高性能 Java 运行时可以提高 Java 应用程序的性能,并减少云浪费。
这是一种常见误解,会让您和团队付出数百万美元的代价。
Java 仍然是构建网站、移动应用程序和分布式数据处理框架等的最热门语言之一(来源:《Java 如今是否仍有实用价值?》Jetbrains,2024 年 7 月),而这一切正是广告科技、金融科技、游戏、电子商务、高性能交易,以及在线旅行与预订行业所必需的。Azul 的 2023 年《Java 现状调查与报告》还显示,Java 在商业企业中几乎得到普遍采用。
而数字业务是在云端运行的。明白我们的意思吗?
可以说,您很可能只关注您使用的 Java 框架,或您正在使用的版本。您会花费时间思考功能的迭代速度以及如何以最快的速度进入市场,同时提供最佳客户体验。 或者,也许您还希望在提供最佳客户体验的同时,将 Java 资产的拥有成本维持在较低水平
Java 就是 Java,不是这样吗?并非如此。
您是否曾经停下来思考过,您使用的是什么 Java 虚拟机? 并非所有 Java 运行时都是相同的。虽然大多数 Java 发行版只是 OpenJDK 的标准副本(包括 Oracle、Temurin 和 Amazon Corretto 的发行版),只对 OpenJDK 进行了普通封装。
然而,一些 JVM 提供了巨大优势。您对 JVM 的选择至关重要。一些 JVM 经过设计,可增强 Java 工作负载,使其运行更快、部署更容易、使用的计算资源更少。
我们发现,Java 的运行速度越快,其使用的计算资源就越少,从而有助于减少云浪费现象的产生。您知道吗? 有一种高性能的 Java 运行时,它经过专门优化,可通过加快代码运行速度来提高应用程序性能,同时减少云浪费。
让我们深入地探讨这个问题
如今,为了应对峰值负载,大多数应用程序通常会进行过度预配置。但是,为什么要支付所有这些资本支出来预配置足以应对峰值负载的硬件,然后再花费运营成本来为这些机器供电、散热和维护?不如让 Amazon、Microsoft 或 Google 等公司为您处理这些事务,您只需像支付电费一样,支付使用费用。
这就是云计算的承诺:通过基于效用的定价模式,以较低的成本运行任务关键型企业应用程序。
遗憾的是,现实中的结果往往有所不同,人们发现,迁移到云端的成本比本地托管更高。为什么会这样,我们又该如何解决?
让我们来专门看看使用 Java 编写的 JVM 应用程序。许多其他语言编写的代码,如 Kotlin、Scala 和 Clojure,经过编译,也可以在 JVM 上运行。
微服务为架构基于云的应用程序提供了现代化的方法。比起开发单一的单体应用程序,我们可以将应用程序拆分成能够松散耦合但又高度内聚的分散服务。这样一来,当一项服务成为性能瓶颈时,我们可以启动该服务的新实例,均衡使用负载,消除瓶颈,而无需更改系统的其他部分。
在这里,JVM 的一项核心功能可能导致云资源的浪费。
为了兑现“一次编写,随处运行”的承诺,Java 应用程序会编译字节码,即针对虚拟机(而非特定处理器)的指令。当 Java 应用程序启动时,JVM 会对其进行分析,找出可编译为原生代码的常用代码热点。这种即时 (JIT) 编译可提供出色的性能,因为 JVM 可以准确地知道代码将如何使用,并据此进行优化。
然而,识别和编译所有常用代码段所需的时间可能比预期更长,这实际上是一个较复杂的多阶段过程。对于 Web 或应用程序服务器等长时间运行的进程来说,这种预热时间通常不是问题。而微服务可能会频繁地启动和停止,以便动态响应负载变化。在微服务提供全部承载能力之前,等待其完成预热将降低这种方法的优势。
常用的解决方案是启动服务的多个实例,并让它们保持运行,以便在需要时立即提供完整性能。这显然非常浪费,而且会产生不必要的云基础设施成本。
如何通过 AOT 或 JIT 编译解决这个问题?
一种方法是使用提前编译 (AOT)。与 JIT 编译不同,这种方法将所有代码直接编译为原生指令。这完全消除了预热,使应用程序从一开始就能达到完整的性能级别。
尽管这听起来像是理想的解决方案,但也具有成本和局限性。
AOT 在编译代码时不知道代码将被如何使用,这限制了优化的可能性。JIT 编译具有分析信息,可以根据应用程序的使用方式进行定制的精确优化。通常,这会带来显著的整体性能提升。
对于短暂的微服务,即所谓的“无服务器计算”,AOT 提供了明显的优势。对于任何至少运行几分钟的服务,JIT 将带来更好的性能,从而降低云计算成本。
AOT 编译 | JIT 编译 |
---|---|
类加载阻止了方法内联 | 可以使用积极的方法内联 |
无运行时字节码生成 | 可以使用运行时字节码生成 |
反射很复杂 | 反射(相对)简单 |
无法使用推测性优化 | 可以使用推测性优化 |
总体性能通常较低 | 总体性能通常较高 |
从一开始就全速运行 | 需要预热时间 |
没有运行时编译代码的 CPU 开销 | 有运行时编译代码的 CPU 开销 |
但是,尽管 AOT 在启动方面具有一系列优势,但 JIT 编译器通常能提供在运行时性能更优的代码。
另一种解决方案是 ReadyNow 预热技术,它是 Platform Prime 高性能 Java 运行时的一部分。
如我们所见,问题在于每次启动微服务实例时,JVM 都必须执行相同的分析,以识别热点、收集分析信息,并将它们编译为原生代码。即使我们之前曾多次以同样的方式使用该微服务,情况也是如此。使用 ReadyNow,服务在生产环境中启动后可以使用实际请求(而非模拟请求)进行预热。当服务完全预热(达到最佳性能水平)后,将收集一个配置文件。此配置文件包含获得该性能水平所需的以下所有信息:热点列表、分析数据,甚至已编译的代码。
当服务需要再次启动时,配置文件将作为执行参数的一部分提供。该配置文件可确保当 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,需要的云资源也更少,这让您可以更好地利用已经承诺的、打折的云资源开支,甚至降低您的云账单费用!