ちょっと話題の記事

[アップデート] Lambda イベントソースに FIFO キューが指定できるようになりました

LambdaイベントソースにFIFOキューが指定可能になりました。序列を保った処理や、重複排除などFIFOキューの便利な機能を使うことで、Lambdaの処理がシンプルに実装できるようになりますね
2019.11.19

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

Lambda のイベントソースに指定できる SQS は、これまで標準キューのみがサポートされていましたが、本日のアップデートで FIFO キューもサポートされるようになったようです。

2019.11.20 公式リリースのリンクを追記しました

Lambda の SQS イベントソースについては、標準キュー対応時の大栗の記事が参考になりますので、あわせてお読みください。

AWS LambdaがSQSをイベントソースとしてサポートしました!

何がうれしいのか

標準キューの場合、メッセージの受信時にはキューに投入された順序は保たれません。また、少なくとも1回の配信サポートであり、場合によっては重複配信されることがあります。そのため、同じメッセージを複数回取得してしまうことを考慮したり、順序を保つ必要がある場合は受信側で何らかの作り込みを行う必要があります。

FIFO(先入れ先出し)キューの場合、名前のとおりキューに投入された順序を保った状態でメッセージを受信することが可能になります。また、FIFO キューの場合、メッセージグループや、重複排除を行うことも可能です。序列を保った処理が作りやすくなると同時に、重複排除などの処理も SQS 側に任せることが出来ます。

2019.11.21 AWS 公式ブログにて Lambda トリガーの場合は、FIFO キューでも1回のみの配信を保証するものではないため、重複が許されない場合は冪等性の実装を推奨する、との記載がありました。詳細については公式ブログをご確認ください。

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.

試してみる

それではさっそく試してみましょう。以下のような手順で進めていきます。

  1. SQS 作成
  2. Lambda 関数の作成
  3. 確認(序列)
  4. 確認(重複排除)

SQS 作成

東京リージョンで FIFO キューを作成します。SQS の管理画面を開き「新しいキューの作成」をクリック。タイプは FIFO キューを選択し、キュー名は .fifo で終わるように指定します。

キューのパラメータはほぼデフォルトのままです。一点、重複排除のみ有効化しました。

Lambda 関数の作成

同じく東京リージョンで FIFO キューをトリガーとした Lambda 関数を作成します。Lambda のダッシュボードから「関数の作成」をクリック。以下のような設定で作成しています。今回は検証環境ということで使用する IAM ロールには AdministratorAccess を付与しています。必要最低限に絞りたい場合は、公式ドキュメントを参照ください。

項目 内容
名前 sqs-event-source
ランタイム Python 3.6
ロール 既存のロールを選択
既存のロール lambda-admin

関数の内容については、大栗の記事同様に以下のとおり設定しました。

from __future__ import print_function
 
def lambda_handler(event, context):
    for record in event['Records']:
       print ("test")
       payload=record["body"]
       print(str(payload))

次にイベントトリガーを設定します。「トリガーを追加」をクリックします。

トリガーに「SQS」を選択し、事前に作成しておいた FIFO キューを指定します。(記憶がうろ覚えですが、以前はここの選択対象に FIFO キューは表示されなかったと思います)。バッチサイズは 5 で検証してみました。

これで FIFO キューをトリガーとした Lambda 関数がセットできました。次にキューにメッセージを投入して、動作を確認していきます。

FIFO キューに投入

以下のように test51test60 まで、キューに 10 件のメッセージを投入しました。(投入の間、SQS イベントトリガーは無効にしました)

イベントトリガーを再有効化して、実行されたログを CloudWatch Logs で確認してみると・・・

おおおーー、当たり前ですが投入した順に処理されていることが確認できましたね!

重複排除を試してみる

今回、重複排除を有効にしているのでこちらも確認してみます。意図的に重複排除 ID --message-deduplication-id 100 をダブらせてキューに投入しました。

$ aws sqs send-message --queue-url $QURL --message-body dupricate-test --message-deduplication-id 100 --message-group-id 1
{
    "MD5OfMessageBody": "014f943d127be2e71810687ca20196e4",
    "SequenceNumber": "18849724831296495872",
    "MessageId": "994fdbf6-c463-4eab-927c-ff12f406a6a1"
}

$ aws sqs send-message --queue-url $QURL --message-body dupricate-test --message-deduplication-id 100 --message-group-id 1
{
    "MD5OfMessageBody": "014f943d127be2e71810687ca20196e4",
    "SequenceNumber": "18849724831296495872",
    "MessageId": "994fdbf6-c463-4eab-927c-ff12f406a6a1"
}

2件投入しましたが、1件しかログがないので、SQS の重複排除が効いているのが確認できました!

イベントログ

イベントログについても確認しておきましょう。以下、公式ドキュメントのサンプルより拝借しています。標準キューのイベントにはなかった、SequenceNumber,MessageGroupId,MessageDeduplicationIdが追加されているようです。event からメッセージグループ ID を抽出して処理を分岐する、といったことも出来そうですね。

{
    "Records": [
        {
            "messageId": "11d6ee51-4cc7-4302-9e22-7cd8afdaadf5",
            "receiptHandle": "AQEBBX8nesZEXmkhsmZeyIE8iQAMig7qw...",
            "body": "Test message.",
            "attributes": {
                "ApproximateReceiveCount": "1",
                "SentTimestamp": "1573251510774",
                "SequenceNumber": "18849496460467696128",
                "MessageGroupId": "1",
                "SenderId": "AIDAIO23YVJENQZJOL4VO",
                "MessageDeduplicationId": "1",
                "ApproximateFirstReceiveTimestamp": "1573251510774"
            },
            "messageAttributes": {},
            "md5OfBody": "e4e68fb7bd0e697a0ae8f1bb342846b3",
            "eventSource": "aws:sqs",
            "eventSourceARN": "arn:aws:sqs:us-east-2:123456789012:fifo.fifo",
            "awsRegion": "us-east-2"
        }
    ]
}

注意点

スループット

FIFO キューによって、メッセージグループ ID や重複排除など利便性は高くなりますが、一方でスループットは標準キューよりも劣ります。高いスループットを求められる環境において FIFO キューが利用できるかどうかについては十分に検証いただく必要がありますのでご注意ください。

リクエスト料金

また、標準キューよりも FIFO キューのほうがリクエスト料金が高くなる点もご注意ください。

無料利用枠を超えた後の 100 万件のリクエストあたりの料金 (月単位)
標準キュー 0.40USD (0.0000004USD/リクエスト)
FIFO キュー 0.50USD (0.0000005USD/リクエスト)

さいごに

Lambda イベントソースに FIFO キューを利用することで、序列を保った処理や、重複排除、メッセージグループといった処理をマネージドサービスに任せることが出来ますね。序列や重複処理といったところは、その後の処理を正しく動作させるための下処理であって、ビジネス的な付加価値を生むところではないかと思います。このような処理は、なるべくマネージドなサービスを活用していただき、本来の付加価値を生む部分に注力して開発していただくのが良いのではないでしょうか。

期待するスループットが FIFO キューでも実現できるのであれば、一度、検討されてみてはいかがでしょうか?

以上!大阪オフィスの丸毛(@marumo1981)でした!