AWS lambda 和 Java 并发

AWS lambda and Java concurrency

众所周知,AWS lambda 可能 重用早期创建的处理程序对象,它确实做到了(参见 FAQ):

Q: Will AWS Lambda reuse function instances?

To improve performance, AWS Lambda may choose to retain an instance of your function and reuse it to serve a subsequent request, rather than creating a new copy. Your code should not assume that this will always happen.


问题是关于 Java 并发的。如果我有一个 class 作为处理程序,请说:

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

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

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

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

EDIT-2 当你想实现某种外部资源的连接池时,就会出现这种问题,所以我想保持与外部资源的连接作为对象变量。果然如愿,就是怕并发问题

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

May AWS lambda use same object concurrently for different calls?

Can instances of handlers of AWS lambda share common heap (memory) or not?

强烈、明确的否定。 AWS Lambda 的处理程序实例甚至无法共享文件(/tmp)。

AWS Lambda 容器可能不能 被重复用于两个或更多同时存在的 Lambda 函数调用,因为这会破坏隔离要求:

Q: How does AWS Lambda isolate my code?

Each AWS Lambda function runs in its own isolated environment, with its own resources and file system view.

“AWS Lambda 运行 我的代码如何?容器模型”部分how lambda functions work 的官方描述中 指出:

After a Lambda function is executed, AWS Lambda maintains the container for some time in anticipation of another Lambda function invocation. In effect, the service freezes the container after a Lambda function completes, and thaws the container for reuse, if AWS Lambda chooses to reuse the container when the Lambda function is invoked again. This container reuse approach has the following implications:

  • Any declarations in your Lambda function code remains initialized, providing additional optimization when the function is invoked again. For example, if your Lambda function establishes a database connection, instead of reestablishing the connection, the original connection is used in subsequent invocations. You can add logic in your code to check if a connection already exists before creating one.

  • Each container provides some disk space in the /tmp directory. The directory content remains when the container is frozen, providing transient cache that can be used for multiple invocations. You can add extra code to check if the cache has the data that you stored.

  • Background processes or callbacks initiated by your Lambda function that did not complete when the function ended resume if AWS Lambda chooses to reuse the container. You should make sure any background processes or callbacks (in case of Node.js) in your code are complete before the code exits.

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

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

据我所知,没有与 Lambda 相关的并发 问题。只有一次调用“拥有”容器。第二次调用将获得另一个容器(或者可能必须等到第一个容器可用)。

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

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