AWS Lambda和Java并发性

61

众所周知,AWS Lambda可能会重复使用已创建的处理程序对象,并且它确实这样做(请参见FAQ):

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

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


问题涉及Java并发。 如果我有一个处理程序类,比如:

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

因此,在这里访问和处理对象变量 foo 是否是线程安全的呢?

换句话说:AWS Lambda 可以同时为不同的调用使用相同的对象吗?

编辑 我的函数在事件驱动源上进行处理,特别是由 API 网关方法调用。

编辑-2 此类问题出现在你想要实现对外部资源的连接池时,因此我希望将连接保持为对象变量。它确实按预期工作,但我担心并发问题。

编辑-3 更具体地说,我想知道:AWS lambda 的处理程序实例是否可以共享公共堆(内存)?我必须指定此附加详细信息,以防止回答列出关于 Java 线程安全对象的显而易见和常见的事情。


在我看来,“保留函数实例并重复使用它”与“使用相同的对象”完全相同,而且很可能是并发的。 - zapl
1
@zapl 当然可以,但是无状态风格并不意味着它们不能是线程安全的。 - Andremoniy
1
@Shibashis 我是在每秒处理数百个请求的情况下使用它的。如果我的上下文是单线程的,我自然不会问这样的问题。 - Andremoniy
2
你的问题不够清晰。如果在你的函数内部,你确保以线程安全的方式访问foo变量,那么你就不必担心lambda函数的重用会导致线程不安全。它只有在函数没有处理其他请求时才会被重用,有点像对象池。每个函数实例都在底层容器中运行,并且是独立的。 - Shibashis
2
@Shibashis,我的问题到底不清楚在哪里?我问了一个明确的问题:在重用处理程序实例的可能性方面,使用对象变量是否是线程安全的?有什么不清楚的吗?关于你评论的第二部分-如果你有链接到描述这些功能的确切文档,你可以提供它作为答案,它将被接受。 - Andremoniy
显示剩余8条评论
3个回答

78
希望AWS Lambda能够在不同的调用中同时使用同一对象吗?AWS Lambda处理程序的实例是否可以共享公共堆(内存)?
强烈且明确的否定。 AWS Lambda处理程序的实例甚至不能共享文件(在 /tmp 中)。
AWS Lambda容器可能不能被重用于Lambda函数的两个或多个并发存在的调用,因为这会破坏隔离要求:
Q:AWS Lambda如何隔离我的代码? “每个AWS Lambda函数都在其自己的隔离环境中运行,具有自己的资源和文件系统视图。”
Lambda函数工作原理的官方描述中,"AWS Lambda如何运行我的代码?容器模型"部分说明了情况。
Lambda函数执行后,AWS Lambda会保留容器一段时间,以期待另一个Lambda函数的调用。实际上,在Lambda函数完成后,服务会冻结容器,并在Lambda函数再次被调用时解冻容器以便重复使用。这种容器重用方法有以下影响:
- Lambda函数代码中的任何声明都将得到初始化,从而为函数再次调用提供额外的优化。例如,如果Lambda函数建立了数据库连接,则在后续调用中将使用原始连接,而不是重新建立连接。您可以在代码中添加逻辑来检查是否已存在连接,然后再创建连接。 - 每个容器在/tmp目录中提供一些磁盘空间。当容器被冻结时,目录内容仍然存在,提供可用于多次调用的短暂缓存。您可以添加额外的代码来检查缓存是否具有您存储的数据。 - 在Lambda函数结束时未完成的后台进程或回调(在Node.js的情况下)将在AWS Lambda选择重用容器时恢复。您应确保代码退出之前,您的代码中的任何后台进程或回调都已完成。

正如您所看到的,当尝试利用容器重用时,在多个并发调用Lambda函数之间不存在关于竞态条件的任何警告。唯一的注意事项是“不要依赖它!”。


赏金将尽快在SO允许的情况下颁发(剩余22小时)。 - Andremoniy

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

0

我发现Lambda没有与并发相关的问题。每个调用只“拥有”一个容器。第二次调用将获得另一个容器(或者可能需要等待第一个容器空闲)。

但是,我没有找到任何保证Java内存可见性问题不会发生。在这种情况下,第一个调用所做的更改可能对第二个调用不可见。或者第二个调用所做的更改之后,第一个调用所做的更改将被写入RAM。

在大多数情况下,可见性问题的处理方式与并发问题相同。因此,我建议开发Lambda函数是线程安全的(或同步的)。至少在AWS给我们保证之前,他们会在每次调用后刷新CPU状态到内存中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接