🐕

SQSを学んでみた

2023/10/07に公開

はじめに

業務で担当しているシステムでSQSを使用している箇所があるんですが、普段触ることもなくどういったサービスなのかいまいち理解できていないところがあリます。
そこでこのページでは、SQSについて調べて学習した内容を記載し、実際にSQSの設定をマネジメントコンソール上とCDKを使用して行なっていきたいと思います。

現時点で認識しているSQSの知識

  • AWSのサービスの一つ。
  • 各サービス間でのリクエストを受け取る、送信する中継役なポジション。
  • 送信先の処理が失敗した際に、失敗したリクエストをDLQとやらに溜め込むことができる。

SQSとは?

調べてみると以下の内容が記載されていた。

  • Simple Queue Serviceの略で、フルマネージドのキューイングサービス。
    • キューイングとは異なるソフトウェア間でデータの送受信する手法の一つで、ソフトウェア間を直接データを渡すのではなく、第三者経由でデータを渡すことで、送信側と受信側が好きなときに処理を行うことができることを指す。

ここまでは、認識していたことと差異はなさそうだが..送信側と受信側が好きな時に処理を行うことができることは初めて知った。
時間がかかる処理なのにリクエストが多くインフラに負荷がかかる際など非常に便利などでは?

SQS固有の言葉

さらに調べていくとSQS固有の言葉が存在することを知った。

  • プロデューサー : メッセージをSQSに送信するアプリケーションのこと
  • コンシューマー : SQSからメッセージをポーリング(取りに行く)アプリケーションのこと
  • メッセージ : 送受信されるデータのこと

SQSの種類

SQSには種類があるようだ。(SQS-AとかSQS-Bとか?)

  • 標準キュー
  • FIFO キュー

これは..基本情報技術者試験で学習した内容に覚えがある言葉があるぞ!
FIFOってもしや先に入れたものを先に出す(First in First out)のことか?
だとするとSQSの種類とは、プロデューサーから受け取ったメッセージをボーリングする際のメッセージ送信順番のこと?


標準キュー

  • スループットは無制限(すごいな)
  • 配信順序はベストエフォートで保証されない(順番が前後する可能性がある)
  • メッセージは最低1回配信する(複数回配信される可能性がある)
    • 複数回同じメッセージが受け取っても悪影響出ないような構成にする必要がある
  • FIFOキューに比べて安価

FIFO キュー

FIFOとはFirst In, First Outの略で、先入れ先出しの意味

  • スループットは1秒あたり300件のメッセージ処理
  • 配信順序は保証される(順番が前後しない)
  • メッセージは必ず1回のみ配信(複数回配信されない)
  • このキューは、配信順序や処理回数が重要な場合に使用される。

※スループット:コンピュータやネットワーク機器が単位時間あたりに処理できるデータ量のこと


なんか微妙に当たっていないような気がする..( ; ; )

一つづつ確認していこう。

スループット

とにかく処理をめちゃくちゃ早くしたい、処理順番は意識したいかで選ぶ種類が変わりそう..
ただこれってボーリングする側のアプリで重複チェックを行えばどうにかできそう。
価格も抑えられるし..ボーリング側の負荷がかかってしまうが許容できればOKかな?

配信順番

うーん、これは明確に順番が保証されているのとされていないとで差別化されてますね。

メッセージの送信回数

ここも複数回送信されて今うのと、必ず一回のみ送信するので、差別かされているが..
上記にも記載した通り、ボーリングする側で対応すればどうにかなりそう。

価格

標準キューの方が安く、FIFOの方が高い。
まあ、FIFOの方が配信順番、メッセージ送信回数を守ってくれるし高いよね。

SQSで行える設定

他のAWSのサービスと同様にSQSを作成する際に、細かな設定を行うことができみたい。

  • 可視性タイムアウト:コンシューマーがメッセージを受信してから可視性タイムアウトの間、他のコンシューマーなどにキューを配信しない
  • 配信遅延 : コンシューマがメッセージを処理するより先にキューがきたときにどのくらいの時間、キューの送信を遅延させるか
  • メッセージ受信待機時間 : メッセージ取得を指定時間だけ待機する
  • メッセージ保持期間 : キューに登録されたメッセージは明示的に削除処理を行われない限りデフォルトで4日間保持
  • 最大メッセージサイズ : キューのメッセージサイズの指定


色々な言葉出てきて混乱しそう..笑

一つづつ確認していこう。

可視性タイムアウト(なんじゃこりゃ?
コンシューマがメッセージをを受け取った際に、指定した時間だけ他のコンシューマにメッセージを送信しないとあるから、送信先が複数あった際に設定する項目のことのよう。

配信遅延

書いてある通り、ボーリングするまでの間の待機時間のことのよう。

メッセージ受信待機時間

これはキュー(SQS)がマネージャにメッセージを受け取りに行く際に指定する待機時間のこと。

メッセージ保持期間

4日間もメッセージを保持してくれるなんて、AWS太っ腹ですね。

最大メッセージサイズ

書いてあるとおり、メッセージの受信容量のことですね。(メールボックスの容量をイメージ)

似たようなAWSサービスとの違い

AWSで似たようなSNSとゆうサービスが存在するらしい。

  • Amazon SQS
    コンシューマはSQSをポーリングして、キューがあれば取得する

  • Amazon SNS
    SNSはコンシューマーを確認せず、とりあえずメッセージを送るプッシュ式。

その他

  • SQSのメッセージについて
    AWS側でメッセージの複数コピーが作成され、複数のアベイラビリゾーンに配置して冗長化されている。必要に応じてユーザーがそれらを利用することも可能。
  • 暗号化について
    Amazon SQSに保存されたメッセージは、暗号化して保存されます。 システム間や機能間で、機密性の高いメッセージのやりとりが可能。(KMSも対応している)
  • 冗長化について
    自動でスケーリングされる。
  • 監視について
    暗号化キーが使用されるたびにAWS CloudTrailに記録されます。その記録をさまざまな監査に対する証跡としても利用できる。

価格

一番気になるところ、ここが高いと正直使う気がなくなってしまいますが..

毎月最初の100万件のリクエストまでは・・・なんと**無料。**それ以降の料金は、すべてのリージョン共通で同じです。

標準キューは100万件あたり0.40USD、つまり0.00000040 USD/リクエストです。しかも単位はリクエストです。1リクエストに10メッセージまで含めることができます。標準キューは100万件あたり0.50USD、つまり0.00000050 USD/リクエストです。

まじか..安すぎない・・・?

次は実際にSQSサービスを利用してみよう。

SQSサービスを利用してみた

今回SQSを利用するに当たって以下のインフラ構成で試していこうと思う。

シンプルにマネージャーにLambda、コンシューマーにLambdaを設置してSQSを試していきたいと思う!

SQSのマネジメントコンソール画面

今回は最低限の設定だけでいいので、デフォルトの設定のまま進めていきます。

作成が完了しました!

これで動作を行いたいのですが、まだマネージャーとコンシューマーのLambdaを作成していないので、作成していきます。

名前は”maneger-sqs”。

公式サイトを参考に作成:https://docs.aws.amazon.com/ja_jp/sdk-for-javascript/v2/developer-guide/sqs-examples-send-receive-messages.html

import { SQSClient, SendMessageCommand } from "@aws-sdk/client-sqs";
  
export const handler = async (event) => {
  // a client can be shared by different commands.
  const client = new SQSClient({ region: "ap-northeast-1" });
  
  const params = {
    MessageBody: "TestMessageBody",
    QueueUrl: "https://sqs.ap-northeast-1.amazonaws.com/351558133335/test-sqs",
    DelaySeconds: 10,
  };
  const command = new SendMessageCommand(params);

  try {
      const data = await client.send(command);
      console.log("sqs log",data)
    } catch (e) {
      console.log("Error", e);
    }

  // TODO implement
  const response = {
    statusCode: 200,
    body: JSON.stringify('SQS Request success!!!'),
  };
  return response;
};

次にコンシューマーを作成。

名前は”consumer-sqs”。
SQSからメッセージを受け取る際は、Recordsから取得する必要があるみたい。
公式サイトを参考:https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/with-sqs-create-package.html

export const handler = async (event) => {
  console.log("receive message")
  event.Records.forEach(record => {
    const { body } = record;
    console.log(body);
  });
  return {};
};

Lambdaを作成したので、SQSに紐づけていきましょう!(LambdaにSQSのアクセス権限を付与することを忘れずに行うこと)

SQSにメッセージが届いた際に送信されるコンシューマーLambdaを設定する。

さてここまでで設定は完了したので、実際に動作確認を行ない、コンシューマに”TestMessageBody”のメッセージログを受信したことを確認できればOK!

CDKでの作成方法

ここまで、マネジメントコンソール上でSQSを作成してきたが、実際の業務ではマネジメントコンソールではなくIacを使用すると思います。
筆者も業務ではCDKを使用してインフラを構築しているので、CDKを使用して上記マネジメントコンソールで作成したインフラ構成を作っていきたいと思う。

必要なもの

以下の内容を用意すればできそう。

  • SQSの作成
    • メッセージ受信時のトリガー設定
  • Lambdaの作成
    • プログラムの用意
    • SQSへのアクセス権限

やってみよう!
CDKのプロジェクト作成後、以下のコードでインフラを構成してみた。
詳しい内容はメモに記載しているが、特に複雑な箇所はなくシンプルに記載できたと思う。
個人的にポリシーを書く場所の理解がまだできていない気が、今後学習していきたい。

import * as cdk from "aws-cdk-lib";
import { Construct } from "constructs";
import { Runtime } from "aws-cdk-lib/aws-lambda";
import { NodejsFunction } from "aws-cdk-lib/aws-lambda-nodejs";
import { Queue } from "aws-cdk-lib/aws-sqs";
import { SqsEventSource } from "aws-cdk-lib/aws-lambda-event-sources";
import { PolicyStatement } from "@aws-cdk/aws-iam";

export class CdkTestSqsStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // SQSの作成
    const testSqs = new Queue(this, "test-sqs", {
      queueName: "hands-on-sqs",
    });

    // SQSへのアクセス権限の作成
    const policy = new cdk.aws_iam.PolicyStatement({
      actions: ["sqs:SendMessage"],
      resources: [testSqs.queueArn],
      effect: cdk.aws_iam.Effect.ALLOW,
    });

    // Lambdaの作成
    const manegerLambda = new NodejsFunction(this, "manerger-lambda", {
      entry: "lambda/manerger-index.ts", // lambda 関数のエントリーポイント
      handler: "handler", // 実行する関数名
      runtime: Runtime.NODEJS_18_X,
      functionName: "manerger-lambda",
      environment: {
        SQS_URL: testSqs.queueUrl,
      },
    });
    const consumerLambda = new NodejsFunction(this, "consumer-lambda", {
      entry: "lambda/consumer-index.ts", // lambda 関数のエントリーポイント
      handler: "handler", // 実行する関数名
      runtime: Runtime.NODEJS_18_X,
      functionName: "consumer-lambda",
    });

    // LamnbdaとSQSの紐付け
    consumerLambda.addEventSource(new SqsEventSource(testSqs));

    // Lambdaに権限付与
    manegerLambda.addToRolePolicy(policy);
  }
}

このコードをデプロイし、manerger-lambdaを実行することで、consumer-lambdaにSQSを通してメッセージが送られるようになります。

最後に

ここまで長くなってきましたが、ここまで記載してないようでSQSの基本的なことは理解できたかと思います。

また学習を進めていく中でこのページは更新していこうと思います。

ここまで読んでいただいてありがとうございました。

参考サイト

https://aws.amazon.com/jp/builders-flash/202105/awsgeek-sqs/?awsf.filter-name=*all

Discussion