web-dev-qa-db-ja.com

(スケジュールされたイベント経由ではなく)ラムダ関数を使用してSQSキューを処理する方法は?

ここに私が仕事をしようとしている簡略化されたスキームがあります:

httpリクエスト->(ゲートウェイAPI +ラムダA)-> SQS->(ラムダB ?????)-> DynamoDB

したがって、次のように機能するはずです:多くのhttp要求(たとえば、毎秒500)からのデータは、ラムダ関数AによってSQSキューに配置されます。次に、他の関数Bがキューを処理します:最大10項目を読み取ります(定期的に)、BatchWriteItemを使用してDynamoDBに書き込みます。

問題は、2番目のラムダ関数をトリガーする方法がわからないことです。頻繁に、1秒間に複数回(または少なくとも1秒間に1回)呼び出す必要があります。なぜなら、キューからすべてのデータをDynamoDB ASAPに取得する必要があるためです(そのため、説明したようにスケジュールされたイベントを介してラムダ関数Bを呼び出します here はオプションではありません)


SQSなしで、DynamoDBに直接書き込みたくないのはなぜですか?

SQSの使用をまったく避けるのは素晴らしいことです。 SQSで対処しようとしている問題は、DynamoDBの調整です。それ自体を調整するのではなく、AWS SDKを使用してDynamoDBにデータを書き込む際の処理方法:レコードを1つずつ書き込み、調整するとき、AWS SDKは書き込みをサイレントに再試行するため、httpクライアントのポイントからのリクエスト処理時間が増加します見る。

したがって、一時的にデータをキューに保存し、応答「200 OK」をクライアントに送信してから、別の関数でキューを処理し、1つのDynamoDBのBatchWriteItem呼び出しで複数のレコードを書き込みます(自動再試行の代わりに未処理のアイテムを返します)スロットルの)。 DynamoDBで受信して保存するレコード間の遅延を増やすのではなく、一部のレコードを失うことを希望します

UPD:誰かが興味を持っているなら、私はaws-sdkがスロットルの場合に自動再試行をスキップする方法を見つけました:特別なパラメータがあります maxRetries 。とにかく、以下に示すようにKinesisを使用します

59
xtx

[これはあなたの明示的な質問に直接答えないので、私の経験ではそれは支持されます:)しかし、私はあなたが解決しようとしている根本的な問題に答えます。]

大量の着信リクエストを取得し、AWS Lambda関数にフィードしてDynamoDBにペースで書き込む方法は、提案されたアーキテクチャのSQSをAmazon Kinesisストリームに置き換えることです。

KinesisストリームはAWS Lambda関数を駆動できます。

Kinesisストリームは、特定のキーに対して配信されたメッセージの順序付けを保証します(順序付けられたデータベース操作に適しています)。

Kinesisストリームを使用すると、並列実行できるAWS Lambda関数の数(パーティションごとに1つ)を指定できます。これは、DynamoDBの書き込み容量と調整できます。

Kinesisストリームは、1つのAWS Lambda関数呼び出しで複数の利用可能なメッセージを渡すことができ、さらなる最適化を可能にします。

注:実際には、AWS Lambdaを直接呼び出すKinesisストリームではなく、Amazon Kinesisストリームから読み取り、関数を呼び出すのはAWS Lambdaサービスです。しかし、Kinesisがそれを駆動するように視覚化する方が簡単な場合があります。ユーザーへの結果はほぼ同じです。

88
Eric Hammond

残念ながら、SQSとLambdaを直接統合することはできません。しかし、まだ心配しないでください。解決策があります!別のAmazonサービスをミックスに追加する必要があり、すべての問題が解決されます。

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

2番目のラムダサービスへのSNS通知をトリガーして開始できます。開始されると、キューを空にし、すべての結果をDynamoDBに書き込むことができます。 Lambdaの考えられるイベントソースをよりよく理解するには、 これらのドキュメント を確認してください。

20
Chris Franklin

2018年6月28日の時点で、SQSを使用してAWS Lambda関数をネイティブにトリガーできるようになりました。回避策はもう必要ありません!

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

14
Trenton

別の解決策は、アイテムをSQSに追加するだけで、イベントを使用して対象のLambda関数を呼び出して非同期にすることです。

非同期Lambdaは、必要な数のアイテムをSQSから取得して処理できます。

また、非同期Lambdaにスケジュールされた呼び出しを追加して、キュー内のエラーのあるアイテムを処理します。

[更新]キューの新しいメッセージでLambdaトリガーを設定できるようになりました

9
loopingz

おそらく、よりコスト効率の高いソリューションは、すべてを(そのまま)SQSに保持し、キューからアイテムを処理するマルチスレッドLambda関数を呼び出すスケジュールされたイベントを実行することでしょうか?

このようにして、キューワーカーは制限を正確に一致させることができます。キューが空の場合、関数は時期尚早に終了するか、単一スレッドでポーリングを開始できます。

この場合、Kinesisは過剰殺害のように聞こえます。たとえば、元の順序は必要ありません。さらに、複数のLambdaを同時に実行することは、1つのマルチスレッドLambdaを実行するよりも確かに高価です。

LambdaはすべてI/Oについてであり、AWSサービスへの外部呼び出しを行うため、1つの関数が非常にうまく適合する可能性があります。

7
Denis Mysenko

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が完了します。

1
Peter Svehla

私は、AWSがSQSがラムダ関数をトリガーできる方法を考え出したと信じています。したがって、SQSを使用して、メッセージの順序を気にしない場合にダイナモへのデータのバーストロードを平滑化できると思います。この新しい更新に関するブログを確認してください: https://aws.Amazon.com/blogs/aws/aws-lambda-adds-Amazon-simple-queue-service-to-supported-event-sources/ =

0
Dipayan

この問題に対する私の解決策は次のとおりです。

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

このソリューションでは、テーブルのストリームを設定する必要があります。ストリームは、作成するLambda関数で処理されます。 SQSなどを使用する必要はありません。

もちろん、これは単純化された設計であり、単純な問題に対してのみ機能します。より複雑なシナリオの場合は、Kinesisを使用します(他の回答で説明されています)。

トピックに関するAWSドキュメントへのリンク です。

0
Mehran