Azul 的全部专注点在于开发 JVM。Azul Platform Prime 非常适合为基于 Java 的微服务部署提供更好的性能并降低成本。
在本文中,您将了解:
- 您可以为基于微服务的应用程序实现更快的 Java 预热
- 更先进的 JIT 编译器可以进一步缩短预热时间
- 优秀的垃圾收集器可以消除那些对用户体验产生负面影响的暂停
Azul Platform Prime 基于开源 OpenJDK 源代码,它是 Java SE 标准的参考实现。为了提供比传统 JVM 更优的性能,Azul 用替代实现替换了部分核心 JVM。具体来说,这包括内存管理系统和部分即时 (JIT) 编译系统。Platform Prime 通过三种方式提升基于 Java 的微服务性能:
- 使用 ReadyNow 加快预热
- 使用云原生编译器缩短预热时间
- 使用 C4 垃圾收集器减少暂停
更快的 JIT 编译可提升性能
Java 源代码被编译为字节码。字节码是 Java 虚拟机 (JVM) 的指令。当 JVM 启动应用程序时,它必须解释每个字节码,将其转换为必要的本机指令和操作系统调用。这种解释会产生开销,导致代码的运行速度比静态编译的代码慢得多。
为了消除这个问题,JVM 在解释字节码时对代码进行分析,记录调用方法的次数。JVM 使用这些分析数据来识别代码中的热点,然后可以使用即时 (JIT) 编译器将其编译为本机指令。随着时间的推移,应用程序执行的大部分代码都会被编译,但到达这一点所需的时间称为应用程序的预热时间。
| 关于 JIT 编译器 |
|---|
传统的 JVM 采用两个 JIT 编译器,称为 C1 和 C2(有时称为客户端和服务器)。每个 JIT 都有其独特的特性,决定了应用程序的性能。
|
从 JDK 7 开始,两种 JIT 都可以通过分层编译用于同一个应用程序。初始阶段使用 C1;随着应用程序运行时间的延长,将使用 C2 来提高性能。
Azul Platform Prime 使用名为 Falcon 的全新改进版本取代了 C2 JIT [图 1]。Falcon JIT 编译器基于开源 LLVM 编译器项目,该项目得到了包括 Intel、NVidia、Apple 和 Sony 在内的众多公司和个人的支持。

1.使用 ReadyNow 缩短预热时间
由于每次应用程序启动时,JVM 都不知道之前执行过程中可能发生的情况,因此应用程序预热的问题更加严重。JVM 必须经历相同的性能分析阶段,执行相同的分析并编译相同的代码段。对于需要频繁重启的应用程序来说,这是有问题的。
解决这个问题的一个显而易见的方法是,在应用程序达到稳定状态且所有必要的代码都已编译完成后,创建已编译代码的快照。应用程序重新启动时,可以重新加载此快照,应用程序可以继续运行,就像它从未停止过一样(从编译的角度来看)。不幸的是,事情并没有这么简单(尽管听起来很简单,但实现实际上很复杂)。JVM 的定义限制了启动时可能发生的事情,尤其是在类加载和初始化方面。其他一些问题使得这种方法不切实际。
了解有关 Java 性能的更多信息
ReadyNow 是 Azul Platform Prime 的一项功能,可从一开始就加速生产环境中的应用程序预热。此时,应用程序的 JIT 状态配置文件会被记录下来。此配置文件记录了当前已加载的类、已初始化的类、指令分析数据(例如 JVM 用于决定编译哪些代码段的数据)以及推测优化失败的详细信息。此外,还会保存已编译代码的副本。
当应用程序重新启动时,可以使用此配置文件让 JVM 和 JIT 执行其通常在应用程序预热阶段执行的所有工作;在这种情况下,这些工作可以在应用程序开始执行 main () 方法中的代码之前完成。这几乎消除了预热阶段,因此应用程序在启动时就可以几乎全速运行 [图 1]。

2.使用云原生编译器进一步缩短预热时间
JIT 编译提供了现代企业应用程序所需的性能,通常优于本机编译的代码,但性能是有代价的。JIT 编译工作负载必须与应用程序共享资源,以便它可以执行事务,这会增加预热时间并降低预热期间的应用程序性能。
如果我们在云端运行,凭借其弹性资源和基于效用的定价模型,为什么不将 JIT 编译器的工作转移到其他地方?
Azul 通过云原生编译器实现了这一点。
云原生编译器创建了一个集中式的 JIT 即服务 [图 2]。当 JVM 需要编译某个方法时,它会将详细信息发送给云原生编译器,而不是在本地执行。这样可以在预热期间实现更大的吞吐量。云原生编译器还可以是一个日志运行进程,用于存储方法编译的结果。当请求同一方法时,启动多个微服务实例,而不是再次编译,可以立即返回存储的代码,从而进一步缩短预热时间。

3.使用 C4 垃圾收集器减少暂停
当执行 Java 应用程序时,JVM 自动处理内存管理。JVM 在实例化新对象时会在堆上分配空间,并在应用程序不再引用该对象时回收该空间。这就是垃圾收集 (GC) 的过程。GC 还会管理堆,通过定期压缩堆、移动对象以确保实时数据连续并消除碎片,从而优化新对象的可用空间。与 C 和 C++ 等依赖程序员显式释放应用程序已用空间的语言相比,GC 具有显著的优势。这种显式释放可能是许多应用程序错误的根源,尤其是当程序员尝试释放无效或不正确的地址时,会导致内存泄漏或应用程序突然终止。
然而,在传统的 JVM 中,GC 也需要暂停应用程序线程,以避免在压缩期间移动对象时损坏数据。这种影响是双重的:首先,它会在 GC 执行工作时给应用程序带来暂停。这些暂停的时长可能从几毫秒到几小时不等,并且时长与分配给堆的内存量成正比,而不是与堆中的数据量成正比。
Azul Platform Prime 使用了不同的 GC 算法,
即连续并发压缩收集器 (C4)。与其他商用 GC 算法不同,
应用程序线程可以在 GC 执行其工作时继续运行
(因此名称中含有“并发”一词)。
其次,这些暂停发生的时间无法准确预测。这会给应用程序带来不确定性行为。在微服务的环境中,这可能导致服务的客户端错误地认为该服务不再可用,即使其 JVM 正在执行 GC。这可能会导致启动新的服务实例,从而在不必要的情况下进一步影响性能。
虽然其他算法(例如并发标记清除 (CMS) 和垃圾优先 (G1))会在应用程序线程运行时执行部分工作,但其他部分仍需要暂停应用程序线程。如果这两种算法无法满足应用程序的内存需求,它们将回退到完整压缩收集周期。这种完整压缩需要应用程序暂停时间,暂停时间与堆大小成正比。
与需要大量命令行选项且难以正确配置的传统垃圾收集器不同,C4 只需设置堆大小即可。C4 的堆空间可从 1Gb 扩展到 20Tb,且不会增加应用程序的暂停时间。
总结
软件开发正在转向云端,并使用微服务以灵活、
可扩展的方式实现这一目标。Java 作为全球最流行的编程语言,
是开发微服务的不二之选。相比其他语言开发的微服务,
Java 微服务也具有诸多优势。Azul Platform Prime 包含一个现代 JVM,该 JVM 对于垃圾收集和部分 JIT 编译系统采用了不同的内部算法。结合 ReadyNow 技术,Azul Platform Prime 可以有效消除微服务性能的预热阶段,使其成为在微服务上进行现代 Java 应用程序开发的理想选择。