配置 AWS SQS/Lambda 触发器以遵守 1:1 策略和最大并发实例数
Configuring AWS SQS/Lambda trigger to honor both 1:1 policy as well as max concurrent instances
Java 8 这里使用 AWS Java SDK 编写一个 Java lambda,它应该执行以响应发送到 SQS 队列的消息。
理想情况下,并且只有一个 lambda 实例将 invoked/executed 用于 每个 发送到 SQS 的记录队列。因此,如果将 5 条消息发送到队列,将触发 5 个 lambda(或者 - 根据我的 lambda 配置 - 我可以设置并发 lambda 的最大数量,在这种情况下,我的期望是 pending/unconsumed SQS 消息将等待下一个可用的 lambda)。
这不是硬性要求,只是理想。
我注意到com.amazonaws.services.lambda.runtime.events.SqsEvent
class中有一个getRecords() : List<SQSMessage>
方法让我有点担心。对我来说,这意味着单个 lambda 实例可能 每次执行超过 1 条 SQS 消息,这再次违背了我想要的行为。
所以我想知道是否有一种方法可以配置 Lambda 触发器,使其仅 ever 每个 SQS 队列消息触发一次,并且还尊重 "max # of concurrent Lambda instances" 设置,使消息在 SQS 中等待,直到 Lambda 准备就绪。作为另一个例子,假设我将并发 Lambda 的最大数量设置为三 (3),并且有 5 条消息同时发送到队列中。在这种情况下,我希望触发 3 个 Lambda,每个处理 5 个排队消息中的一个,并且 5 个消息中的 2 个将等待这 3 个 Lambda 中的一个完成,以便另一个可以触发并接收它们。
这可以吗?或者 Lambda 只是 "decide" (?) 以某种方式自行提交给给定 Lambda 执行的消息数?如果是这样,有人知道这是怎么决定的吗?
Getrecords 是从 1 到源的最大可能记录的函数。批量大小由 lambda event source mapping 控制。如果您将其设置为 1,您的 lambda 将始终收到一个只有一个元素的记录数组。
处理消息的 lambda 数取决于您为 lambda 设置的并发限制。请记住,如果您允许的并发 lambda 数量小于您在任何时候拥有的 sqs 消息数量,您可能会在 cloudwatch 指标中看到很多限制异常。如果那是所需的行为,您可以忽略它们。
您还可以增加 sqs 配置的可见性超时,以确保相同的消息不会传递到另一个 lambda,而它已经被一个 lambda 处理。
TL;DR
正如@joseph 已经正确指出的那样,您可以使用 事件源映射 并将 BatchSize 设置为 1。这将使 getRecords()
return 最多 1 SQSMessage。为了一次最多处理 1 条消息,您必须将 Lambda 函数的 reserved concurrency 设置为 1。
但是,正如也正确指出的那样,这对于 standard SQS 队列来说并不是最优的。事件源映射将 运行 变成一些 TooManyRequestsException: Rate Exceeded 错误,这些错误记录到 CloudWatch Logs。
要在不依赖 Lambda 函数节流的情况下使用正确的一次一条消息顺序处理模式,请使用 AWS 博客 post [1] 中所述的 SQS FIFO 队列。
它说:"Total concurrency is equal to or less than the number of unique MessageGroupIds in the SQS FIFO queue"。也就是说,您可以为您的 SQS FIFO 队列恰好配置一个 MessageGroupId,以便:
- 每条 SQS 队列消息只触发一次 Lambda(因为 batchSize = 1)
- 同时还遵守恰好为 1 的 "max # of concurrent Lambda instances"(因为并发计数 = #unique 消息组 ID = 1)
因此,唯一消息组 ID 的数量是最大值。 SQS FIFO 队列的事件源映射的并发 Lambda 调用数。
更多信息
Java Lambda 库
据我所知,AWS 提供了一组 POJO(例如库 aws-lambda-java-events 中的 SQSEvent
)[ 2] 为了处理传入的 SQS 事件 [3]。 SQS 事件由 Lambda 事件源映射传递并反序列化为给定的 POJO。 POJO SQSEvent 的文档也可在 JavaDoc.io [4] 获得,源代码可在 GitHub [5] 获得。
方法 getRecords()
return 是 SQSMessage
对象的列表,因为 AWS Lambda 事件源映射确实可以提供 1 到 10 条 SQS 消息。
Lambda 事件源映射
事件源映射已创建并配置了特定于源类型的属性。当我们查看 SQS 集成时,我们必须只考虑 SQS 特定的属性。这些主要是:BatchSize和EventSourceArn。有关完整列表,请参阅 [6]。如果某个属性不适用于 SQS 源类型,则其描述以关键字 (Streams)
.
开头
如果要限制使用 getRecords()
检索的 SQS 消息的数量,则必须设置 BatchSize。默认值为 10。
Lambda 缩放
如文档 [7] 中所述,Lambda 并发限制可用于限制 Lambda 函数并发处理的 SQS 消息批处理的数量。但是,这不会阻止事件源映射调用 Lambda 函数。至少,我找不到任何相反的官方来源-如果我错了请纠正我。
也就是说,如果SQS队列被大量使用,会抛出很多节流错误(代码429)。
可以通过指示事件源按顺序处理消息来解决此问题。这是通过使用 Amazon SQS FIFO 事件源实现的。这是一个相当新的功能。 [8]
总结
总而言之,我会推荐给:
- 使用 FIFO 类型而不是标准类型的 SQS 队列
- 使用 BatchSize 设置为 1 的事件源映射
- 在所有 SQS 中对 MessageGroupId 属性使用相同的值 SendMessage API 调用 [9]
- 熟悉 SQS FIFO 队列和标准队列之间的差异 [10][11] - 包括定价差异 [12]
- 不必设置预留并发,因为它由 FIFO 队列的事件源映射处理
参考资料
[1] https://aws.amazon.com/blogs/compute/new-for-aws-lambda-sqs-fifo-as-an-event-source/
[2] https://docs.aws.amazon.com/lambda/latest/dg/with-sqs-create-package.html#with-sqs-example-deployment-pkg-java
[3] https://docs.aws.amazon.com/lambda/latest/dg/with-sqs.html
[4] https://javadoc.io/static/com.amazonaws/aws-lambda-java-events/2.2.2/com/amazonaws/services/lambda/runtime/events/SQSEvent.html
[5] https://github.com/aws/aws-lambda-java-libs/blob/master/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/SQSEvent.java
[6] https://docs.aws.amazon.com/lambda/latest/dg/API_CreateEventSourceMapping.html#API_CreateEventSourceMapping_RequestBody
[7] https://docs.aws.amazon.com/lambda/latest/dg/configuration-concurrency.html
[8] https://aws.amazon.com/about-aws/whats-new/2019/11/aws-lambda-supports-amazon-sqs-fifo-event-source/?nc1=h_ls
[9] https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html
[10] https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/using-messagegroupid-property.html
[11] https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/FIFO-queues.html#FIFO-queues-moving
[12] https://aws.amazon.com/sqs/pricing/?nc1=h_ls
Java 8 这里使用 AWS Java SDK 编写一个 Java lambda,它应该执行以响应发送到 SQS 队列的消息。
理想情况下,并且只有一个 lambda 实例将 invoked/executed 用于 每个 发送到 SQS 的记录队列。因此,如果将 5 条消息发送到队列,将触发 5 个 lambda(或者 - 根据我的 lambda 配置 - 我可以设置并发 lambda 的最大数量,在这种情况下,我的期望是 pending/unconsumed SQS 消息将等待下一个可用的 lambda)。
这不是硬性要求,只是理想。
我注意到com.amazonaws.services.lambda.runtime.events.SqsEvent
class中有一个getRecords() : List<SQSMessage>
方法让我有点担心。对我来说,这意味着单个 lambda 实例可能 每次执行超过 1 条 SQS 消息,这再次违背了我想要的行为。
所以我想知道是否有一种方法可以配置 Lambda 触发器,使其仅 ever 每个 SQS 队列消息触发一次,并且还尊重 "max # of concurrent Lambda instances" 设置,使消息在 SQS 中等待,直到 Lambda 准备就绪。作为另一个例子,假设我将并发 Lambda 的最大数量设置为三 (3),并且有 5 条消息同时发送到队列中。在这种情况下,我希望触发 3 个 Lambda,每个处理 5 个排队消息中的一个,并且 5 个消息中的 2 个将等待这 3 个 Lambda 中的一个完成,以便另一个可以触发并接收它们。
这可以吗?或者 Lambda 只是 "decide" (?) 以某种方式自行提交给给定 Lambda 执行的消息数?如果是这样,有人知道这是怎么决定的吗?
Getrecords 是从 1 到源的最大可能记录的函数。批量大小由 lambda event source mapping 控制。如果您将其设置为 1,您的 lambda 将始终收到一个只有一个元素的记录数组。
处理消息的 lambda 数取决于您为 lambda 设置的并发限制。请记住,如果您允许的并发 lambda 数量小于您在任何时候拥有的 sqs 消息数量,您可能会在 cloudwatch 指标中看到很多限制异常。如果那是所需的行为,您可以忽略它们。
您还可以增加 sqs 配置的可见性超时,以确保相同的消息不会传递到另一个 lambda,而它已经被一个 lambda 处理。
TL;DR
正如@joseph 已经正确指出的那样,您可以使用 事件源映射 并将 BatchSize 设置为 1。这将使 getRecords()
return 最多 1 SQSMessage。为了一次最多处理 1 条消息,您必须将 Lambda 函数的 reserved concurrency 设置为 1。
但是,正如也正确指出的那样,这对于 standard SQS 队列来说并不是最优的。事件源映射将 运行 变成一些 TooManyRequestsException: Rate Exceeded 错误,这些错误记录到 CloudWatch Logs。
要在不依赖 Lambda 函数节流的情况下使用正确的一次一条消息顺序处理模式,请使用 AWS 博客 post [1] 中所述的 SQS FIFO 队列。 它说:"Total concurrency is equal to or less than the number of unique MessageGroupIds in the SQS FIFO queue"。也就是说,您可以为您的 SQS FIFO 队列恰好配置一个 MessageGroupId,以便:
- 每条 SQS 队列消息只触发一次 Lambda(因为 batchSize = 1)
- 同时还遵守恰好为 1 的 "max # of concurrent Lambda instances"(因为并发计数 = #unique 消息组 ID = 1)
因此,唯一消息组 ID 的数量是最大值。 SQS FIFO 队列的事件源映射的并发 Lambda 调用数。
更多信息
Java Lambda 库
据我所知,AWS 提供了一组 POJO(例如库 aws-lambda-java-events 中的 SQSEvent
)[ 2] 为了处理传入的 SQS 事件 [3]。 SQS 事件由 Lambda 事件源映射传递并反序列化为给定的 POJO。 POJO SQSEvent 的文档也可在 JavaDoc.io [4] 获得,源代码可在 GitHub [5] 获得。
方法 getRecords()
return 是 SQSMessage
对象的列表,因为 AWS Lambda 事件源映射确实可以提供 1 到 10 条 SQS 消息。
Lambda 事件源映射
事件源映射已创建并配置了特定于源类型的属性。当我们查看 SQS 集成时,我们必须只考虑 SQS 特定的属性。这些主要是:BatchSize和EventSourceArn。有关完整列表,请参阅 [6]。如果某个属性不适用于 SQS 源类型,则其描述以关键字 (Streams)
.
如果要限制使用 getRecords()
检索的 SQS 消息的数量,则必须设置 BatchSize。默认值为 10。
Lambda 缩放
如文档 [7] 中所述,Lambda 并发限制可用于限制 Lambda 函数并发处理的 SQS 消息批处理的数量。但是,这不会阻止事件源映射调用 Lambda 函数。至少,我找不到任何相反的官方来源-如果我错了请纠正我。
也就是说,如果SQS队列被大量使用,会抛出很多节流错误(代码429)。 可以通过指示事件源按顺序处理消息来解决此问题。这是通过使用 Amazon SQS FIFO 事件源实现的。这是一个相当新的功能。 [8]
总结
总而言之,我会推荐给:
- 使用 FIFO 类型而不是标准类型的 SQS 队列
- 使用 BatchSize 设置为 1 的事件源映射
- 在所有 SQS 中对 MessageGroupId 属性使用相同的值 SendMessage API 调用 [9]
- 熟悉 SQS FIFO 队列和标准队列之间的差异 [10][11] - 包括定价差异 [12]
- 不必设置预留并发,因为它由 FIFO 队列的事件源映射处理
参考资料
[1] https://aws.amazon.com/blogs/compute/new-for-aws-lambda-sqs-fifo-as-an-event-source/
[2] https://docs.aws.amazon.com/lambda/latest/dg/with-sqs-create-package.html#with-sqs-example-deployment-pkg-java
[3] https://docs.aws.amazon.com/lambda/latest/dg/with-sqs.html
[4] https://javadoc.io/static/com.amazonaws/aws-lambda-java-events/2.2.2/com/amazonaws/services/lambda/runtime/events/SQSEvent.html
[5] https://github.com/aws/aws-lambda-java-libs/blob/master/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/SQSEvent.java
[6] https://docs.aws.amazon.com/lambda/latest/dg/API_CreateEventSourceMapping.html#API_CreateEventSourceMapping_RequestBody
[7] https://docs.aws.amazon.com/lambda/latest/dg/configuration-concurrency.html
[8] https://aws.amazon.com/about-aws/whats-new/2019/11/aws-lambda-supports-amazon-sqs-fifo-event-source/?nc1=h_ls
[9] https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html
[10] https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/using-messagegroupid-property.html
[11] https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/FIFO-queues.html#FIFO-queues-moving
[12] https://aws.amazon.com/sqs/pricing/?nc1=h_ls