当用作 lambda 触发器时,SQS fifo 队列不能确保单次交付

SQS fifo queues not ensuring single time delivery when used as lambda trigger

我有一个 fifo 队列,它作为 lambda 的触发器,并且这个 fifo 队列没有其他消费者。

我希望我的 lambda 不接收任何重复项,因为我确保我的消息具有 uniqueid 并且启用了基于内容的重复数据删除,以便没有重复项。但正如文档所说

Amazon SQS FIFO queues ensure that the order of processing follows the message order within a message group. However, it does not guarantee only once delivery when used as a Lambda trigger. If only once delivery is important in your serverless application, it’s recommended to make your function idempotent. You could achieve this by tracking a unique attribute of the message using a scalable, low-latency control database like Amazon DynamoDB.

这是否意味着我的 lambda 会收到重复项,即使启用了重复数据删除,它也是 fifo 队列的唯一使用者?

即使您有一个 lambda 函数作为消费者,取决于您的 lambda 函数的并发设置,也可以有多个调用。这意味着在给定时间,多个调用可以在您的 SQS 队列中选择消息。

对此的简单解决方法是将 lambda 函数的并发性设置为 1,这样在给定时间只允许调用一次。所以队列中的消息会被依次处理。

(但是,如果队列中有大量消息需要处理,这将导致瓶颈。)

这里有两件事你似乎混合在一起。

  • 一方面,有SQS交付模型。使用 SQS FIFO 队列,您正确地注意到它启用 exactly-once 传递。

  • 另一方面,还有 Lambda 函数的执行模型。执行模型是 at-least-once。顺便说一下,这与任何并发设置无关。

Lambda 可能多次执行一个函数有多种原因。最值得注意的是,Lambda 具有内置的重试功能,并且独立于 SQS FIFO 队列。根据可能发生的错误类型以及您的 Lambda 代码具有何种外部可观察到的副作用,您可能会在一次实际调用中多次看到您的代码 运行。

也就是说,发送到 SQS FIFO 队列的消息可能最终 被 Lambda 处理不止一次还有其他原因。例如,如果您的 Lambda 函数需要比队列或消息的 VisibilityTimeout 设置更长的时间来完成处理它收到的整个批次,那么所有这些消息将在队列中再次变为可见,并且您的 Lambda 函数的另一次调用 (当然,不仅仅是"probably")再次收到这些消息。

所以底线是:您需要在 Lambda 中编写幂等代码 - 不是因为 SQS FIFO(它确实允许防止重复传送),而是因为 Lambda 重试和消息成为的可能性由于处理缓慢,在队列中再次可见(它总是 at-least-once 执行模型)。