如何使用lambda函数处理SQS队列(不是通过预定事件)?

时间:2016-01-08 13:52:15

标签: amazon-web-services aws-lambda amazon-sqs

以下是我正在尝试的简化方案:

  

http请求 - > (Gateway API + lambda A) - > SQS - > (lambda B.   ?????) - > DynamoDB

所以它应该如图所示:来自许多http请求的数据(例如,每秒高达500) 由我的lambda函数A放入SQS队列。然后另一个函数B处理队列: 最多可读取10个项目(在某些期刊基础上),并使用BatchWriteItem将它们写入DynamoDB。

问题在于我无法弄清楚如何触发第二个lambda函数。它应该被频繁调用,每秒多次(或至少每秒一次),因为我需要队列中的所有数据尽快进入DynamoDB(这就是为什么通过所描述的调度事件调用lambda函数B的原因{ {3}}不是一个选项)

为什么我不想在没有SQS的情况下直接写入DynamoDB?

对我来说,完全避免使用SQS会很棒。我试图用SQS解决的问题是DynamoDB限制。甚至没有限制自己,而是在使用AWS SDK将数据写入DynamoDB时处理它的方式:当逐个编写记录并限制它们时,AWS SDK会静默重试写入,从而导致增加来自http客户端的请求处理时间&#39 ; s观点。

所以我想暂时将数据存储在队列中,发送响应" 200 OK"回到客户端,然后通过单独的函数处理队列, 使用一个DynamoDB的BatchWriteItem调用写入多个记录(其中 返回未处理的项目,而不是在限制的情况下自动重试)。 我甚至更愿意丢失一些记录,而不是增加接收和存储在DynamoDB中的记录之间的延迟

UPD:如果有人感兴趣,我已经找到了如何在限制情况下使aws-sdk跳过自动重试:有一个特殊参数here。无论如何,将按照以下建议使用Kinesis

7 个答案:

答案 0 :(得分:88)

[这并没有直接回答你的明确问题,所以根据我的经验,它会被贬低:)但是,我会回答你试图解决的根本问题。]

我们采用大量传入请求并将其提供给AWS Lambda函数以便以节奏的方式写入DynamoDB的方式是用Amazon Kinesis流替换建议架构中的SQS。

Kinesis流可以驱动AWS Lambda函数。

Kinesis流保证为任何给定密钥排序所传递的消息(对于有序的数据库操作很有用)。

Kinesis流允许您指定可以并行运行的AWS Lambda函数(每个分区一个),这可以与您的DynamoDB写入容量协调。

Kinesis流可以在一个AWS Lambda函数调用中传递多个可用消息,从而允许进一步优化。

注意:实际上从Amazon Kinesis流中读取的AWS Lambda服务然后调用该函数,而不是直接调用AWS Lambda的Kinesis流;但有时可以更容易想象出Kinesis驾驶它。对用户的结果几乎相同。

答案 1 :(得分:20)

不幸的是,你无法直接集成SQS和Lambda。但是不要担心太多。有一个解决方案!您需要在混合中添加另一个亚马逊服务,所有问题都将得到解决。

http requests --> (Gateway API + lambda A) --> SQS + SNS --> lambda B --> DynamoDB

您可以触发第二个lambda服务的SNS通知以启动它。启动后,它可以排空队列并将所有结果写入DynamoDB。为了更好地理解Lambda的可能事件源,请查看these docs

答案 2 :(得分:14)

自2018年6月28日起,您现在可以使用SQS本地触发AWS Lambda函数。不再需要解决方法!

https://aws.amazon.com/blogs/aws/aws-lambda-adds-amazon-simple-queue-service-to-supported-event-sources/

答案 3 :(得分:7)

也许更具成本效益的解决方案是将所有内容保存在SQS中(实际上是这样),然后运行调度事件,该事件调用处理队列中项目的多线程Lambda函数?

这样,您的队列工作人员可以完全匹配您的限制。如果队列为空,则函数可以提前完成或在单线程中开始轮询。

对于这种情况,Kinesis听起来像是一种过度杀戮 - 例如,你不需要原始订单。另外同时运行多个Lambdas肯定比仅运行一个多线程Lambda更昂贵。

您的Lambda将全部关于I / O,对AWS服务进行外部调用,因此一个功能可能非常适合。

答案 4 :(得分:1)

这是我从SQS队列收集消息的方式:

package au.com.redbarn.aws.lambda2lambda_via_sqs;

import java.util.List;

import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.lambda.runtime.events.SQSEvent;
import com.amazonaws.services.lambda.runtime.events.SQSEvent.SQSMessage;

import lombok.extern.log4j.Log4j2;

@Log4j2
public class SQSConsumerLambda implements RequestHandler<SQSEvent, String> {

    @Override
    public String handleRequest(SQSEvent input, Context context) {

        log.info("message received");

        List<SQSMessage> records = input.getRecords();

        for (SQSMessage record : records) {
            log.info(record.getBody());
        }

        return "Ok";
    }
}

将您的DynamoDB代码添加到handleRequest(),然后完成Lambda B。

答案 5 :(得分:0)

这是我解决这个问题的方法:

HTTP request --> DynamoDb --> Stream --> Lambda Function

在此解决方案中,您必须为表设置流。流将使用您将要编写的Lambda函数进行处理。无需使用SQS或其他任何东西。

当然,这是一个简化的设计,它只适用于简单的问题。对于更复杂的场景,请使用Kinesis(如其他答案中所述)。

这里是link to AWS documentation on the topic

答案 6 :(得分:0)

我相信AWS现在提出了一种SQS可以触发lambda函数的方法。因此,我想我们可以使用SQS平滑突发数据到发电机的负载,以防您不关心消息顺序。在以下新更新中查看他们的博客:https://aws.amazon.com/blogs/aws/aws-lambda-adds-amazon-simple-queue-service-to-supported-event-sources/