1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【AWSプロフェッショナルへの道】現役エンジニアが贈るクラウド実践ガイド - 第12回

1
Posted at

メッセージングの基本!SQSとSNSで疎結合システムを実現する

こんにちは!現役エンジニアのakrです。

【AWSプロフェッショナルへの道】現役エンジニアが贈るクラウド実践ガイド」の第12回をお届けします。前回はAPI Gatewayを深掘りし、セキュアで高機能なAPIの構築方法を学びました。これで、外部からのリクエストを安全かつ効率的に処理する仕組みが整いましたね。

今回は、分散システムを構築する上で非常に重要な概念である「メッセージング」に焦点を当てます。AWSが提供する主要なメッセージングサービスであるAmazon SQS (Simple Queue Service)Amazon SNS (Simple Notification Service) を徹底的に解説し、これらを使ってシステム間の連携を「疎結合」にする方法を学びます。

「なぜ直接連携じゃダメなの?」「キューとトピックって何が違うの?」といった疑問を持つかもしれません。SQSとSNSは、システム全体の信頼性、スケーラビリティ、耐障害性を向上させるために不可欠なサービスです。本記事では、メッセージングの基本概念から、SQSとSNSのそれぞれの特徴、利用シーン、そして実践的な連携方法までを網羅的に学び、堅牢な分散システムを構築するスキルを身につけます。

メッセージングの基本!SQSとSNSで疎結合システムを実現する - visual selection.png


1. 疎結合システムとメッセージングの必要性

まず、なぜ「疎結合システム」が重要なのか、そしてそれを実現するために「メッセージング」がどのように役立つのかを理解しましょう。

従来のモノリシックなアプリケーションでは、すべてのコンポーネントが密接に連携しており、ある部分の障害がシステム全体に影響を与える可能性がありました。また、特定のコンポーネントの負荷が増大すると、システム全体のスケーラビリティが制限される問題もありました。

密結合と疎結合

特徴 密結合システム 疎結合システム
コンポーネント間の関係 直接的な依存関係、同期的な呼び出し 独立性が高く、非同期的な通信が主
障害の影響 あるコンポーネントの障害が全体に波及しやすい 障害が他のコンポーネントに波及しにくい
スケーラビリティ 特定のコンポーネントのボトルネックが全体に影響 各コンポーネントを独立してスケール可能
柔軟性 変更やデプロイが全体に影響しやすい 各コンポーネントを独立して変更・デプロイ可能
直接的なAPI呼び出し、共有データベースへの直接アクセス メッセージキュー、イベントバスを介した通信

メッセージングの役割

メッセージングは、システム内の異なるコンポーネントが直接通信するのではなく、メッセージを介して間接的に通信するための仕組みです。これにより、コンポーネント間の依存関係が減り、システム全体が疎結合になります。

  • 非同期処理: メッセージを送信した側は、受信側がすぐに処理を完了するのを待つ必要がありません。これにより、応答速度の向上や、大量のリクエストのバッファリングが可能になります。
  • 耐障害性: 受信側が一時的にダウンしていても、メッセージはキューに保持されるため、システム全体が停止することなく、後で処理を再開できます。
  • スケーラビリティ: メッセージキューに溜まったメッセージを、複数の受信側コンポーネントで並行して処理できるため、負荷に応じて処理能力を柔軟にスケールできます。
  • システムの分離: 各コンポーネントはメッセージの送受信方法だけを知っていればよく、相手の内部実装を知る必要がありません。

AWSでは、このメッセージングを実現するための主要なサービスとしてSQSSNSを提供しています。


2. Amazon SQS (Simple Queue Service) とは?

Amazon SQSは、フルマネージドなメッセージキューサービスです。アプリケーション間でメッセージを送信、保存、受信するための信頼性の高い、スケーラブルなキューを提供します。

SQSの仕組み

  1. プロデューサー (Producer): メッセージをSQSキューに送信するコンポーネントです。
  2. キュー (Queue): メッセージを一時的に保存する場所です。
  3. コンシューマー (Consumer): SQSキューからメッセージを受信し、処理するコンポーネントです。

SQSの主な特徴

  • フルマネージド: キューの管理、スケーリング、可用性の確保をAWSが代行します。
  • 非同期通信: プロデューサーとコンシューマーが直接通信せず、キューを介して非同期にメッセージをやり取りします。
  • 信頼性と耐久性: メッセージは複数のサーバーとアベイラビリティゾーン (AZ) に冗長化して保存され、高い信頼性と耐久性を提供します。
  • スケーラビリティ: メッセージの量に応じて自動的にスケールし、大量のメッセージを処理できます。
  • 2種類のキュー:
    • 標準キュー (Standard Queue):
      • 特徴: 高いスループットと「少なくとも1回」の配信保証を提供します。メッセージの順序は厳密には保証されません(ベストエフォート)。
      • 用途: 大量のメッセージを高速に処理したい場合(例: ログ処理、非同期タスク実行)。
    • FIFOキュー (First-In-First-Out Queue):
      • 特徴: メッセージの順序が厳密に保証され、「ちょうど1回」の配信保証を提供します。標準キューよりもスループットは低いですが、順序性が重要な場合に利用します。
      • 用途: 注文処理、金融取引など、メッセージの順序が重要な場合。
  • 可視性タイムアウト (Visibility Timeout): コンシューマーがメッセージを処理している間、他のコンシューマーがそのメッセージを受信しないように、一時的にメッセージをキューから「見えなくする」時間です。
  • デッドレターキュー (Dead-Letter Queue - DLQ): 何度処理しても失敗するメッセージを隔離するためのキューです。これにより、正常なメッセージの処理が滞るのを防ぎ、失敗したメッセージを後で分析・再処理できます。

3. Amazon SNS (Simple Notification Service) とは?

Amazon SNSは、フルマネージドなパブリッシュ/サブスクライブ型メッセージングサービスです。メッセージを複数のサブスクライバー(購読者)に同時に配信するために使用されます。

SNSの仕組み

  1. パブリッシャー (Publisher): メッセージをSNSトピックに送信するコンポーネントです。
  2. トピック (Topic): メッセージの論理的なアクセスポイントであり、メッセージのカテゴリを定義します。
  3. サブスクライバー (Subscriber): SNSトピックを購読し、メッセージを受信するエンドポイントです。
    • サポートされるサブスクライバータイプ: Lambda関数、SQSキュー、HTTP/Sエンドポイント、Eメール、SMS、モバイルプッシュ通知など。

SNSの主な特徴

  • フルマネージド: トピックの管理、スケーリング、可用性の確保をAWSが代行します。
  • ファンアウト機能: 1つのメッセージを複数の異なるタイプのサブスクライバーに同時に配信できます。
  • メッセージフィルタリング: サブスクライバーは、特定の属性を持つメッセージのみを受信するようにフィルタリングポリシーを設定できます。
  • 信頼性と耐久性: メッセージは複数のサーバーとAZに冗長化して保存され、高い信頼性と耐久性を提供します。
  • 低レイテンシー: ほぼリアルタイムでメッセージを配信します。
  • 用途:
    • イベント通知: システムイベント(例: EC2インスタンスの状態変化、S3へのファイルアップロード)の通知。
    • ファンアウト: 1つのイベントを複数の異なる処理(ログ記録、データ分析、通知送信など)に分岐させたい場合。
    • モバイルプッシュ通知: モバイルアプリへのプッシュ通知。

4. SQSとSNSの使い分けと連携

SQSとSNSはどちらもメッセージングサービスですが、その役割と利用シーンは異なります。

  • SQS: メッセージのキューイングと非同期処理に特化しています。メッセージを一時的に保存し、コンシューマーが都合の良いときに処理できるようにします。**1対1(または1対多だが、各メッセージは1つのコンシューマーが処理)**の非同期タスク処理に適しています。
  • SNS: メッセージの配信とファンアウトに特化しています。1つのメッセージを複数の受信者に同時に通知します。1対多の通知に適しています。

SQSとSNSの連携

SQSとSNSは組み合わせて利用することで、より強力な疎結合システムを構築できます。
一般的なパターンは、SNSトピックをSQSキューのプロデューサーとして設定することです。

連携のメリット:

  • 複数のコンシューマーへのファンアウト: SNSトピックにメッセージをパブリッシュすると、そのトピックを購読している複数のSQSキューに同じメッセージが配信されます。これにより、1つのイベントを複数の独立した処理フローに分岐させることができます。
  • 耐障害性の向上: SNSがメッセージを複数のSQSキューに配信することで、特定のコンシューマーやキューが一時的に利用不能になっても、メッセージが失われるリスクを低減できます。また、SQSキューがメッセージを保持するため、コンシューマーはメッセージを確実に処理できます。
  • 処理の分離: 各SQSキューに異なるコンシューマー(Lambda関数、EC2インスタンスなど)を接続することで、それぞれの処理を完全に分離し、独立してスケールさせることができます。

5. 実践!SNSとSQSを連携させてイベント通知システムを構築しよう

それでは、実際にSNSトピックとSQSキューを作成し、連携させてみましょう。今回は、SNSトピックにメッセージをパブリッシュすると、それがSQSキューに配信され、最終的にLambda関数で処理されるというシンプルなイベント通知システムを構築します。

5.1. SQSキューの作成

まず、SNSからのメッセージを受け取るためのSQSキューを作成します。

  1. AWSマネジメントコンソールにサインインし、「SQS」サービスに移動します。
  2. キューを作成」をクリックします。
  3. タイプ: 「標準」を選択します。(今回は順序性は不要なため)
  4. 名前: my-event-queue
  5. 設定:
    • 可視性タイムアウト: デフォルトの30秒のままでOKです。
    • メッセージ保持期間: デフォルトの4日間のままでOKです。
    • (※DLQの設定は今回はスキップします)
  6. 「キューを作成」をクリック。

5.2. Lambda関数の作成 (SQSキューをポーリング)

SQSキューからメッセージを受信し、処理するためのLambda関数を作成します。

  1. AWSマネジメントコンソールで「Lambda」サービスに移動します。

  2. 関数の作成」をクリックします。

  3. 作成方法: 「一から作成」を選択します。

  4. 基本情報:

    • 関数名: sqs-message-processor
    • ランタイム: 「Node.js 20.x」を選択します。
    • 実行ロール: 「既存のロールを使用する」を選択し、前回作成した lambda-basic-execution-role を選択します。
      • 重要: このロールに、SQSキューからのメッセージ読み取り権限sqs:ReceiveMessage, sqs:DeleteMessage, sqs:GetQueueAttributesなどを含むAmazonSQSReadOnlyAccessポリシーまたはカスタムポリシー)を追加する必要があります。IAMコンソールでlambda-basic-execution-roleにポリシーをアタッチしてください。
    • 「関数の作成」をクリック。
  5. 関数コードの編集:

    • index.mjs を開き、以下の内容に置き換えます。
    // index.mjs (Node.js 20.x)
    export const handler = async (event) => {
      console.log('Received SQS event:', JSON.stringify(event, null, 2));
    
      for (const record of event.Records) {
        console.log('Message Body:', record.body);
        // ここでメッセージの実際の処理を行います
        // 例: データベースへの書き込み、別のサービス呼び出しなど
        try {
          const messageData = JSON.parse(record.body);
          console.log('Parsed Message:', messageData);
          // SNSからのメッセージの場合、record.bodyはSNSのJSON形式
          if (messageData.Type === 'Notification' && messageData.Message) {
            console.log('SNS Notification Message:', messageData.Message);
            // さらにSNSメッセージのMessageフィールドをパースする必要がある場合
            try {
              const innerMessage = JSON.parse(messageData.Message);
              console.log('Parsed Inner SNS Message:', innerMessage);
            } catch (e) {
              console.log('SNS Message is not JSON:', messageData.Message);
            }
          }
        } catch (e) {
          console.error('Error parsing message body:', e);
          console.log('Raw message body:', record.body);
        }
      }
    
      return {
        statusCode: 200,
        body: JSON.stringify('Messages processed successfully!'),
      };
    };
    
    • event.Records配列には、SQSキューから受信した複数のメッセージが含まれる可能性があります。各メッセージのbodyには、SNSから転送された場合はSNSのJSON形式のメッセージが含まれます。
    • コードを編集したら、「Deploy」ボタンをクリックして変更を保存します。
  6. SQSトリガーの設定:

    • Lambda関数のデザイナー画面(概要)で、「トリガーを追加」をクリックします。
    • ソースを選択: 「SQS」を選択します。
    • SQSキュー: 先ほど作成した my-event-queue を選択します。
    • バッチサイズ: 10 (一度に処理するメッセージの最大数。デフォルトでOK)
    • 「追加」をクリック。

5.3. SNSトピックの作成

メッセージをパブリッシュするためのSNSトピックを作成します。

  1. AWSマネジメントコンソールで「SNS」サービスに移動します。
  2. 左のナビゲーションペインから「トピック」を選択し、「トピックを作成」をクリックします。
  3. タイプ: 「標準」を選択します。(FIFOトピックはFIFOキューと連携する場合に利用)
  4. 名前: my-event-topic
  5. 「トピックを作成」をクリック。

5.4. SNSトピックとSQSキューの購読設定

SNSトピックからSQSキューにメッセージが配信されるように購読設定を行います。

  1. 作成したSNSトピック(my-event-topic)を選択します。
  2. サブスクリプションを作成」をクリックします。
  3. プロトコル: 「Amazon SQS」を選択します。
  4. エンドポイント: 先ほど作成したSQSキューのARN(Amazon Resource Name)を入力します。
    • SQSコンソールで my-event-queue を選択し、「詳細」タブの「ARN」をコピーして貼り付けます。
    • 例: arn:aws:sqs:ap-northeast-1:123456789012:my-event-queue
  5. 「サブスクリプションを作成」をクリック。

これで、SNSトピックにパブリッシュされたメッセージが、自動的にSQSキューに転送されるようになります。

5.5. SNSトピックにメッセージをパブリッシュして動作確認

SNSトピックにメッセージを送信し、SQSキューとLambda関数が連携して動作することを確認しましょう。

  1. SNSコンソールで、作成したトピック(my-event-topic)を選択します。

  2. メッセージをパブリッシュ」をクリックします。

  3. 件名 (オプション): Test Message from SNS

  4. メッセージ本文: {"data": "This is a test event from SNS!"} (JSON形式で入力)

  5. 「メッセージをパブリッシュ」をクリック。

  6. Lambda関数のログを確認:

    • Lambdaコンソールで sqs-message-processor 関数を選択します。
    • モニター」タブをクリックし、「CloudWatch Logs のログを表示」をクリックします。
    • 最新のログストリームを開くと、Lambda関数がSQSキューからメッセージを受信し、ログに出力していることが確認できます。
      • Received SQS event: にイベント全体が表示され、その中にパブリッシュしたメッセージ本文が含まれているはずです。

これで、SNS → SQS → Lambda という疎結合なイベント駆動型システムが構築できました!


6. メッセージングのベストプラクティス

  • 冪等性の確保: メッセージ処理は再試行される可能性があるため、同じメッセージを複数回処理しても問題ないように、Lambda関数などのコンシューマー側で冪等性を確保しましょう。
  • デッドレターキュー (DLQ) の活用: 処理に失敗したメッセージを隔離し、後で分析・再処理するために、SQSキューやLambda関数にDLQを設定しましょう。
  • 適切なキュー/トピックタイプの選択: 順序性や厳密な配信保証が必要な場合はFIFO、それ以外は標準キュー/トピックを選択しましょう。
  • バッチ処理の最適化: SQSからLambdaへのトリガー設定でバッチサイズを調整し、Lambdaの呼び出し回数を減らしてコストを最適化しましょう。
  • メッセージサイズの考慮: SQS/SNSにはメッセージサイズの上限があります(256KB)。大きなデータを扱う場合は、S3にデータを保存し、S3オブジェクトのパスをメッセージとして送るなどの工夫が必要です。
  • セキュリティ: SQSキューやSNSトピックへのアクセスは、IAMポリシーで厳密に制御しましょう。
  • モニタリング: CloudWatchでSQSキューのメッセージ数、可視性タイムアウト、SNSトピックのパブリッシュ数、配信失敗率などを監視し、異常を検知できるようにしましょう。

まとめ

今回は、分散システムにおけるメッセージングの重要性と、AWSの主要なメッセージングサービスであるAmazon SQSとAmazon SNSについて深く掘り下げました。

  • 疎結合システムは、コンポーネント間の依存関係を減らし、システム全体の信頼性、スケーラビリティ、耐障害性を向上させます。
  • SQSは、メッセージキューとして非同期処理と耐障害性を提供し、SNSはパブリッシュ/サブスクライブモデルで多対多のメッセージ配信を実現します。
  • SQSとSNSを連携させることで、1つのイベントを複数の処理フローに分岐させ、より堅牢なイベント駆動型システムを構築できることを学びました。
  • 実際にSNS → SQS → Lambdaという連携システムを構築し、メッセージのフローを確認しました。

SQSとSNSは、マイクロサービスアーキテクチャやイベント駆動型アプリケーションを構築する上で不可欠なツールです。これらを活用することで、システム全体の複雑性を軽減し、各コンポーネントを独立して開発・運用できるようになります。ぜひ、ご自身のシステム設計にメッセージングの概念を取り入れてみてください。


この記事が皆さんのAWS学習の一助となれば幸いです。

もしこの記事が役に立ったと感じたら、ぜひ「いいね」👍をお願いします!励みになります!

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?