AWS lambda 和 Java 并发

众所周知,AWS lambda 可能会重用处理程序的早期创建对象,并且它确实做到了(请参阅常见问题解答):

问:AWS Lambda 是否会重用函数实例?

为了提高性能,AWS Lambda 可能会选择保留函数的实例并重复使用它来为后续请求提供服务,而不是创建新副本。您的代码不应假定这种情况总是会发生。


问题与并发性有关。如果我有一个处理程序的类,比如说:Java

public class MyHandler {
    private Foo foo;
    public void handler(Map<String,String> request, Context context) {
       ...
    }
}

那么,在这里访问和使用对象变量是否是线程安全的?foo

换句话说:AWS lambda 是否可以将同一对象并发用于不同的调用?

编辑我的函数在基于事件的源上进行处理,特别是由 API Gateway 方法调用。

编辑-2当您想要实现与外部资源的某种连接池时,会出现这样的问题,因此我想将与外部资源的连接保持为对象变量。它实际上可以按预期工作,但我害怕并发问题。

编辑-3更具体地说,我想知道:AWS lambda的处理程序实例是否可以共享公共堆(内存)?我必须指定这个额外的细节,以防止通过列出有关java线程安全对象的明显和众所周知的事情来回答。


答案 1

AWS lambda 是否可以将同一对象并发用于不同的调用?

AWS lambda 的处理程序实例是否可以共享公共堆(内存)?

一个强有力的,明确的否定。AWS Lambda 处理程序的实例甚至无法共享文件(在 中)。/tmp

AWS Lambda 容器不能重用于 Lambda 函数的两个或多个并发现有调用,因为这会破坏隔离要求:

问:AWS Lambda 如何隔离我的代码?

每个 AWS Lambda 函数都在其自己的隔离环境中运行,并具有自己的资源和文件系统视图。

“AWS Lambda 如何运行我的代码?容器模型“lambda 函数如何工作的官方描述中指出:

执行 Lambda 函数后,AWS Lambda 会将容器维护一段时间,以期待另一个 Lambda 函数调用。实际上,如果 AWS Lambda 选择在再次调用 Lambda 函数时重用容器,则该服务会在 Lambda 函数完成后冻结容器,并解冻容器以供重用。此容器重用方法具有以下含义:

  • Lambda 函数代码中的任何声明都将保持初始化状态,从而在再次调用函数时提供额外的优化。例如,如果您的 Lambda 函数建立数据库连接,而不是重新建立连接,而是在后续调用中使用原始连接。您可以在代码中添加逻辑,以便在创建连接之前检查连接是否已存在。

  • 每个容器在 /tmp 目录中提供一些磁盘空间。当容器被冻结时,目录内容将保留,从而提供可用于多次调用的瞬态缓存。您可以添加额外的代码来检查缓存中是否包含您存储的数据。

  • 如果 AWS Lambda 选择重用容器,则由 Lambda 函数启动的后台进程或回调在函数结束时未完成,则会恢复。在代码退出之前,应确保代码中的任何后台进程或回调(如果是 Node.js)都已完成。

如您所见,在尝试利用容器重用时,绝对不会出现有关 Lambda 函数的多个并发调用之间的争用条件的警告。唯一的注意事项是“不要依赖它!


答案 2

在使用 AWS Lambda 时,利用执行上下文重用绝对是一种做法(请参阅 AWS Lambda 最佳实践)。但这不适用于并发执行,因为对于并发执行,将创建一个新容器,从而创建新的上下文。简而言之,对于并发执行,如果一个处理程序更改了该值,则另一个处理程序将不会获取新值。


推荐