Lambda调用方式 - 异步调用

当异步调用Lambda时,不用实时等待Lambda返回结果。一些AWS服务,例如S3、SNS,会使用异步调用Lambda的方式来对事件进行处理。

异步调用方式由于对调用者立即返回结果,所以不会让调用者等待而造成负担。例如同时往S3上传了10万个文件, 假设S3 Event调用Lambda时采用同步调用的方式,那么S3必须等待这1万个文件处理完成,这会对S3后端将造成很大负担

下面的图展示了异步调用Lambda的原理——当事件触发时,Lambda将事件信息保存到内部队列(Event Queue)里,再进行后续的处理:

image-20220308203104370

image-20220402202657495

异步调用测试

在上一节,我们使用了同步调用方式来运行hello-world:

aws lambda invoke --function-name hello-world response.json

使用--invocation-type Event参数,可以将Lambda执行方式变成异步调用

aws lambda invoke --function-name hello-world --invocation-type Event response.json

image-20220402203915623

观察到命令行立刻返回结果: StatusCode 202,sleep 5秒的逻辑在后台会继续运行,在命令行不会得到后续程序处理的结果数据。

错误处理

和同步调用方式相比,异步调用时Lambda增加了自动错误处理机制,当代码执行出错时:

  • 最多2次retry。第1次retry间隔1min,第二次2min。由于相同的代码可能会被执行多次,所以应用要保证是幂等(idempotent)的。
  • 如果执行出错,将在Cloudwatch Logs里看到有多次调用
  • 可以创建一个Dead Letter Queue,收集执行Lambda失败时的相关信息

上面的特性将在下面的实验中展现的淋漓尽致


错误处理 - demo

hello-world代码更新为:

import json
import time

def lambda_handler(event, context):
    # TODO implement
    print("hello world")
    raise Exception('Something wrong in the backend')

由于主动抛出异常——raise Exception,上面的代码运行后将触发错误,用于触发Lambda异步调用时错误处理的机制。


在Cloud 9中调用hello-world函数:image-20220402205549937

耐心等待三分钟,到CloudWatch Log中查看Lambda最新的日志流:

image-20220402214223151

image-20220402210135888

我们只调用了一次Lambda,但在后台能够看到有三次执行(1次调用执行 + 2次retry)。且第二次执行在间隔1min后,第三次执行在间隔2min后。


虽然Lambda保证了自动重试,但假设我们的程序执行了三次后依然失败,还是需要将信息收集到死信队列(dead letter queue), 用于分析出错原因或者触发后续的处理机制

进入SQS页面,创建SQS,用于作为Lambda的死信队列:

image-20220402205841793

点击创建。

由于Lambda需要将死信发送到SQS,所以Lambda要有访问SQS的权限。为Lambda的Role添加权限:

image-20220402205913713

image-20220402205939897

添加AmazonSQSFullAccess权限,这样Lambda具有访问SQS的能力:

image-20220402210003335

编辑Lambda异步调用的相关配置:

image-20220402210235530

将Dead-letter queue设置为刚才我们创建的SQS,并保存:

image-20220402210310834

重新执行两条测试,在第二条测试时,传入event数据(第一条测试的event数据实际为{}):

aws lambda invoke --function-name hello-world --invocation-type Event response.json
aws lambda invoke --function-name hello-world --invocation-type Event --cli-binary-format raw-in-base64-out --payload '{"key-test": "value-test"}' response.json

等待三分钟后,查看SQS,发现有两条新的消息:

image-20220402211550221

查看消息内容:

image-20220402211609772

image-20220402211628753

上面两次执行Lambda都失败,得到两条死信消息:

image-20220402211645758

在执行Lambda失败后,传入的Event数据会被记录到死信列队里:

image-20220402211659814