SNSとSQSのFanoutで、メッセージが並列に届くことを確認してみた

1%の不安を解消します。
2021.05.07

SNSとSQSを組み合わせるファンアウトはよく使われます。いざ、実際に使うときになって、ふと思ってしまいました。

「あれ? 同じデータが来るよね? 一部だけじゃないよね?」と。

SNSとSQSによるファンアウト

99%問題なしと思っていますが、念のため、実際に試してみました。

おすすめの方

  • SNSとSQSのファンアウトで並列にイベント実行されるか知りたい方
  • SNSとSQSのファンアウトをCloudFormatinで作成したい方

実験用のサーバーレスアプリを作成する

ざっくり構成図

1つのSNSに2つのSQSと2つのLambdaを繋げます。このときのLambdaのログを確認します。

SNSとSQSとLambdaによるファンアウト

sam init

sam init \
    --runtime python3.8 \
    --name sns-sqs-test \
    --app-template hello-world \
    --package-type Zip

SAMテンプレート

下記を作成しています。

  • SNSトピック
  • SQS
  • SQSポリシー
  • Lambda1とロググループ
  • Lambda2とロググループ

なお、Lambda1とLambda2は、同じソースコードを使用します。

template.yaml

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: sns-sqs-test

Resources:

  # SNS

  TestTopic:
    Type: AWS::SNS::Topic
    Properties:
      Subscription:
        - Protocol: sqs
          Endpoint: !GetAtt Test1Queue.Arn
        - Protocol: sqs
          Endpoint: !GetAtt Test2Queue.Arn

  # SQS

  Test1Queue:
    Type: AWS::SQS::Queue
    Properties:
      VisibilityTimeout: 10

  Test2Queue:
    Type: AWS::SQS::Queue
    Properties:
      VisibilityTimeout: 10

  QueuePolicy:
    Type: AWS::SQS::QueuePolicy
    Properties:
      Queues:
        - !Ref Test1Queue
        - !Ref Test2Queue
      PolicyDocument:
        Statement:
          - Action:
              - "sqs:SendMessage"
            Effect: "Allow"
            Resource: "*"
            Principal:
              Service: sns.amazonaws.com

  # Lambda

  Test1Function:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: hello_world/
      Handler: app.lambda_handler
      Runtime: python3.8
      Timeout: 10
      Events:
        SQS:
          Type: SQS
          Properties:
            BatchSize: 1
            Queue: !GetAtt Test1Queue.Arn

  Test1FunctionLogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: !Sub /aws/lambda/${Test1Function}

  Test2Function:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: hello_world/
      Handler: app.lambda_handler
      Runtime: python3.8
      Timeout: 10
      Events:
        SQS:
          Type: SQS
          Properties:
            BatchSize: 1
            Queue: !GetAtt Test2Queue.Arn

  Test2FunctionLogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: !Sub /aws/lambda/${Test2Function}

Lambdaコード

eventの内容をログ出力するだけです。

app.py

import json

def lambda_handler(event, context):
    print(json.dumps(event))

デプロイ

sam build

sam deploy \
    --stack-name Sns-Sqs-Test-Stack \
    --s3-bucket cm-fujii.genki-deploy \
    --capabilities CAPABILITY_NAMED_IAM \
    --no-fail-on-empty-changeset

SNSでメッセージを発行して、動作を確認する

SNSトピックにメッセージを発行する

1つのメッセージを発行します。2つのLambdaに同じメッセージが届くことを期待します。

SNSトピックにメッセージを発行する

Lambda1のログを確認する

バッチリ届いていました。

Lambda1のログ

Lambda2のログを確認する

2つ目のLambdaにも、問題なく届いていました。

Lambda2のログ

というわけで、メッセージは並列に届く

SNSとSQSによるファンアウト

さいごに

SNSとSQSを組合わあせたアーキテクチャについては、下記のブログが非常に参考になります。ぜひご覧ください。