自定义 Lambda 函数的 Java 运行时启动行为 - AWS Lambda

自定义 Lambda 函数的 Java 运行时启动行为

本页将介绍特定于 AWS Lambda 中 Java 函数的设置。您可以使用这些设置来自定义 Java 运行时系统启动行为。这样可以减少总体函数延迟并提高总体函数性能,而无需修改任何代码。

了解 JAVA_TOOL_OPTIONS 环境变量

在 Java 中,Lambda 支持 JAVA_TOOL_OPTIONS 环境变量以在 Lambda 中设置其他命令行变量。您可以通过多种方式使用此环境变量,例如自定义分层编译设置。下一个示例演示了如何针对此使用案例使用 JAVA_TOOL_OPTIONS 环境变量。

示例:自定义分层编译设置

分层编译是 Java 虚拟机(JVM)的一项功能。您可以使用特定的分层编译设置来充分利用 JVM 的即时(JIT)编译器。通常,C1 编译器经过优化,可缩短启动时间。C2 编译器经过优化以获得最佳整体性能,但它也会占用更多内存,并且需要更长的时间才能实现。分层编译有 5 个不同级别。在级别 0 上,JVM 解释 Java 字节代码。在级别 4 上,JVM 使用 C2 编译器来分析在应用程序启动期间收集的分析数据。随着时间的推移,它会监控代码使用情况以确定最佳优化。

自定义分层编译级别有助于您优化 Java 函数的性能。对于执行速度较快的小型函数,将分层编译级别设置为 1 级可以通过让 JVM 使用 C1 编译器来帮助提升冷启动性能。该设置可以快速生成优化原生代码,但它不生成任何分析数据,也从不使用 C2 编译器。对于计算密集型的大型函数,将分层编译设置为 4 级可最大限度地提高整体性能,但会带来额外的内存消耗以及每次在 Lambda 执行环境预置后首次调用时的额外优化工作。

对于 Java 11 运行时及更低版本,Lambda 使用默认的 JVM 分层编译设置。对于 Java 17 和 Java 21,Lambda 将 JVM 配置为默认在级别 1 停止分层编译。从 Java 25 开始,Lambda 仍会默认在级别 1 停止分层编译,除非使用 SnapStart 或预置并发,在这种情况下,将使用默认的 JVM 设置。这提高了 SnapStart 和预置并发的性能,同时又不会产生冷启动的负面影响,因为在这些情况下,分层编译是在调用路径之外进行的。为了充分发挥这一优势,您可以在函数初始化过程中使用引导 - 执行代码路径,以便在拍摄 SnapStart 快照之前或在预置并发执行环境被预先配置时触发 JIT。有关更多信息,请参阅博客文章利用 SnapStart 结合先进的引导策略来优化 AWS Lambda 的冷启动性能

自定义分层编译设置(控制台)
  1. 在 Lambda 控制台中打开函数页面。

  2. 选择要为其自定义分层编译的 Java 函数。

  3. 选择配置选项卡,然后从左侧菜单中选择环境变量

  4. 选择编辑

  5. 选择添加环境变量

  6. 对于键,输入 JAVA_TOOL_OPTIONS。对于值,输入 -XX:+TieredCompilation -XX:TieredStopAtLevel=1

    使用 Lambda 控制台添加 JAVA_TOOL_OPTIONS 环境变量
  7. 选择保存

注意

您也可以使用 Lambda SnapStart 来缓解冷启动问题。SnapStart 使用执行环境的缓存快照来显著提高启动性能。有关 SnapStart 的功能、限制和支持的区域的更多信息,请参阅 使用 Lambda SnapStart 提高启动性能

示例:使用 JAVA_TOOL_OPIONS 自定义 GC 行为

Java 11 运行时系统使用串行垃圾收集器(GC)实现垃圾回收。默认情况下,Java 17 运行时系统也使用串行 GC。不过,在 Java 17 中,您也可以使用 JAVA_TOOL_OPTIONS 环境变量来更改默认 GC。您可以在 Parallel GC 和 Shenandoah GC 之间进行选择。

例如,如果工作负载会使用更多内存和多个 CPU,则考虑使用 Parallel GC 来获得更好的性能。为此,您可以将以下内容附加到 JAVA_TOOL_OPTIONS 环境变量的值中:

-XX:+UseParallelGC

如果您的工作负载中包含大量临时对象,则通过启用 Java 25 中引入的 Shenandoah 垃圾回收器代际模型,您可能会降低内存消耗从而获得益处。为此,可以将以下内容附加到 JAVA_TOOL_OPTIONS 环境变量的值中:

-XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational

Log4Shell 的 Log4j 补丁

适用于 Java 8、11、17 和 21 的 Lambda 运行时包括 Log4j(一款广受欢迎的 Java 日志记录框架)中的 Log4Shell 漏洞(CVE-2021-44228)的修复补丁。此修复补丁会产生冷启动性能开销。如果您使用的是 Log4j 的补丁版本(版本 2.17.0 或更高版本),则可以禁用此补丁以提高冷启动性能。要禁止此补丁,请将环境变量 AWS_LAMBDA_DISABLE_CVE_2021_44228_PROTECTION 设置为 true

从 Java 25 版本开始,Lambda 运行时不再包含 Log4Shell 补丁。您必须确认您使用的是 Log4j 版本 2.17.0 或更高版本。

提前编译(AOT)和 CDS 缓存

从 Java 25 版本开始,Lambda 运行时为 Java 运行时接口客户端(RIC)配备了提前编译(AOT)缓存。RIC 是一个会主动从 Lambda 运行时 API 轮询事件的运行时组件。这可以提高冷启动性能。

AOT 缓存特定于 JVM 版本。当 Lambda 更新托管运行时时,它还会更新 RIC 的 AOT 缓存。但是,如果您部署自己的 AOT 缓存,则在运行时更新后,这些缓存可能会失效,或者导致出现意外情况。因此,我们强烈建议在使用托管运行时时不要使用 AOT 缓存。要使用 AOT 缓存,您需要使用容器映像来部署您的函数。

AOT 缓存不能与类数据共享(CDS)缓存一起使用。如果您在 Lambda 函数中部署了 CDS 缓存,则 Lambda 会禁用 AOT 缓存。