Amazon SQS: メッセージキュー

Amazon シンプル キュー サービス (SQS) は管理されたメッセージ キューです。 プロデューサはキューにメッセージを送信し、コンシューマはポーリングを通じてメッセージを取得します。 基本的なセマンティクスは次のとおりです ポイントツーポイント: キュー内のメッセージ 一度に 1 人の消費者によって読み取られます (最初に受け取った消費者が他の消費者からそれを「隠します」 を介して 可視性タイムアウト).

標準キューと FIFO キューの比較

SQS は 2 つのモードを提供します。

  • 標準キュー: 無制限のスループット、少なくとも 1 回の配信 (重複可能)、ベストエフォート型の注文 (保証されません)。大規模なユースケース向け 重複は消費者側で管理可能です。
  • FIFOキュー: 1 回限りの配信 (自動重複排除による) MessageDeduplicationId)、 保証されたソート メッセージグループ、スループットはリクエストごとに 3,000 msg/s に制限されます (バッチ処理あり)。順序付けと重複が重要なユースケース (金融取引など)。
// SQS Producer Java con AWS SDK v2
import software.amazon.awssdk.services.sqs.*;
import software.amazon.awssdk.services.sqs.model.*;

public class SqsProducer {

    private final SqsClient sqsClient = SqsClient.builder()
        .region(Region.EU_WEST_1)
        .build();

    // Standard Queue: invio semplice
    public void sendToStandardQueue(String queueUrl, String messageBody) {
        SendMessageResponse response = sqsClient.sendMessage(
            SendMessageRequest.builder()
                .queueUrl(queueUrl)
                .messageBody(messageBody)
                // Delay di consegna (0-900 secondi)
                .delaySeconds(0)
                // Attributi del messaggio per filtraggio (SNS subscription filter)
                .messageAttributes(Map.of(
                    "eventType", MessageAttributeValue.builder()
                        .stringValue("OrdineCreato")
                        .dataType("String")
                        .build()
                ))
                .build()
        );
        System.out.println("Messaggio inviato: " + response.messageId());
    }

    // FIFO Queue: richiede MessageGroupId e MessageDeduplicationId
    public void sendToFifoQueue(String queueUrl, String ordineId, String payload) {
        sqsClient.sendMessage(
            SendMessageRequest.builder()
                .queueUrl(queueUrl)  // url deve terminare in .fifo
                .messageBody(payload)
                // Group: tutti i messaggi dello stesso ordine vengono elaborati in ordine
                .messageGroupId("ordine-" + ordineId)
                // Deduplication: prevenzione duplicati (valido 5 minuti)
                .messageDeduplicationId(ordineId + "-" + System.currentTimeMillis())
                .build()
        );
    }
}

SQS コンシューマ: ポーリングと可視性のタイムアウト

// SQS Consumer con Long Polling e gestione DLQ
public class SqsConsumer {

    private final SqsClient sqsClient = SqsClient.builder()
        .region(Region.EU_WEST_1).build();

    public void poll(String queueUrl) {
        while (true) {
            // Long polling: aspetta fino a 20 secondi per nuovi messaggi
            // Riduce le chiamate vuote (e i costi) rispetto al short polling
            ReceiveMessageResponse response = sqsClient.receiveMessage(
                ReceiveMessageRequest.builder()
                    .queueUrl(queueUrl)
                    .maxNumberOfMessages(10)        // max 10 per chiamata
                    .waitTimeSeconds(20)             // long polling
                    .visibilityTimeout(30)           // 30s per elaborare
                    .messageAttributeNames("All")
                    .build()
            );

            for (Message message : response.messages()) {
                try {
                    processMessage(message.body());

                    // Successo: elimina dalla coda
                    sqsClient.deleteMessage(
                        DeleteMessageRequest.builder()
                            .queueUrl(queueUrl)
                            .receiptHandle(message.receiptHandle())
                            .build()
                    );

                } catch (Exception e) {
                    // Non eliminare: SQS rirenderà visibile il messaggio
                    // dopo il visibility timeout. Dopo maxReceiveCount tentativi
                    // finisce nella DLQ configurata
                    System.err.println("Errore, il messaggio tornera visibile: " + e.getMessage());
                }
            }
        }
    }
}

Amazon SNS: ファンアウト Pub/Sub

Amazon シンプル通知サービス (SNS) パターンを実装します パブリッシュ/サブスクライブ: プロデューサーがメッセージを投稿する SNSの話題をSNSで並行して皆様にお届けします メンバー(加入者)。 SNS トピックには数千の購読者が含まれる場合があります。 Lambda、SQS、HTTP エンドポイント、電子メール、SMS、モバイル プッシュ。

SNS + SQS パターン (SNSファンアウト) は最も一般的なパターンの 1 つです AWS アーキテクチャ: SNS は同じイベントを複数の SQS キューに並行して配信します。 そして、各キューは異なるコンシューマー (異なるマイクロサービス) にサービスを提供します。

# SNS + SQS Fan-Out: un evento raggiunge 3 servizi in parallelo

# Struttura:
# SNS Topic "ordini-topic"
#   |--- SQS "inventario-queue" --- Lambda inventario
#   |--- SQS "pagamenti-queue"  --- Lambda pagamenti
#   |--- SQS "notifiche-queue"  --- Lambda notifiche email

# Terraform
resource "aws_sns_topic" "ordini" {
  name = "ordini-topic"
}

resource "aws_sqs_queue" "inventario" {
  name = "inventario-queue"
  visibility_timeout_seconds = 60
  redrive_policy = jsonencode({
    deadLetterTargetArn = aws_sqs_queue.inventario_dlq.arn
    maxReceiveCount     = 3
  })
}

resource "aws_sns_topic_subscription" "ordini_inventario" {
  topic_arn = aws_sns_topic.ordini.arn
  protocol  = "sqs"
  endpoint  = aws_sqs_queue.inventario.arn

  # Filter policy: questa subscription riceve SOLO OrdineCreato
  filter_policy = jsonencode({
    eventType = ["OrdineCreato"]
  })
}
// SNS Publisher Java
import software.amazon.awssdk.services.sns.*;
import software.amazon.awssdk.services.sns.model.*;

public class SnsPublisher {

    private final SnsClient snsClient = SnsClient.builder()
        .region(Region.EU_WEST_1).build();

    public void publishOrdineCreato(String topicArn, OrdineCreato event) throws Exception {
        String messageJson = new ObjectMapper().writeValueAsString(event);

        PublishResponse response = snsClient.publish(
            PublishRequest.builder()
                .topicArn(topicArn)
                .message(messageJson)
                // Message attributes per subscription filter
                .messageAttributes(Map.of(
                    "eventType", MessageAttributeValue.builder()
                        .stringValue("OrdineCreato")
                        .dataType("String")
                        .build()
                ))
                // Subject visibile solo nelle email
                .subject("Nuovo ordine: " + event.getOrdineId())
                .build()
        );
        System.out.println("SNS Message ID: " + response.messageId());
    }
}

完全な比較

特性 SQS SNS イベントブリッジ
モデル ポイントツーポイント (キュー) ファンアウト (パブ/サブ) コンテンツベースのルーティング
受信者 一度に 1 人の消費者 すべて並行して登録されています ルールによるターゲット (1-5)
フィルター 誰も(すべてを奪う) メッセージ属性 (限定的) 任意の JSON フィールドのイベント パターン
仕分け 保証されたFIFO(FIFOキュー) No No
重複排除 はい (FIFO キュー) No No
最大。スループット 無制限(標準) 無制限 リージョンあたり 1,000 万イベント/秒
レイテンシ ミリ秒 (ポーリング) < 1s (プッシュ) < 500ms
スキーマレジストリ No No はい (統合)
イベントアーカイブ/リプレイ No No Si
パートナー統合SaaS No No はい (パートナー 35 名以上)
100 万メッセージあたりのコスト ~0.40ドル ~0.50ドル ~$1.00

意思決定ガイド: いつどれを使用するか

次の場合に SQS を使用します。

  • 必要がある 負荷分散 同じタイプの複数のコンシューマー間 (例: 同じキューを処理する 5 つの Lambda)
  • メッセージを詳しく説明する必要がある ちょうど一度だけ (FIFOキュー)
  • 必要がある 背圧: コンシューマが遅いとメッセージがキューに溜まる
  • 欲しいですか? 配達遅延 (1メッセージあたり最大15分)
  • 従来のキュー モデルを使用するレガシー システムを統合している場合

SNS は次のような場合に使用します。

  • 同じイベントが到達する必要があります 複数のシステムを並行して実行する (ファンアウトパターン)
  • 送信する必要があります 通知 (電子メール、SMS、モバイルプッシュ、HTTP Webhook)
  • SNS と SQS を組み合わせて、各コンシューマのファンアウトとバッファリングの両方を実現

次の場合に EventBridge を使用します。

  • 必要がある インテリジェントルーティング ペイロードの内容に基づいて
  • と統合する AWSのサービス (EC2、S3、RDS) または SaaSパートナー (Zendesk、Shopify、Stripe)
  • あなたはそれが欲しいです スキーマレジストリ およびスキームガバナンス
  • 必要がある イベントのアーカイブとリプレイ
  • を構築する 企業イベントバス 集中ルーティングを使用する

SNS + SQS + ラムダ パターン: 完全なスタック

# Architettura tipica per un microservizio event-driven su AWS
#
# Client HTTP
#    |
#    v
# API Gateway / Lambda "ordini-api"
#    | pubblica su
#    v
# SNS Topic "ordini-events"
#    |-- filtra "OrdineCreato" --> SQS "inventario-queue" --> Lambda "inventario-handler"
#    |-- filtra "OrdineCreato" --> SQS "notifiche-queue"  --> Lambda "email-notifier"
#    |-- tutti i tipi         --> SQS "audit-queue"       --> Lambda "audit-logger"
#
# Ogni SQS ha la sua DLQ per messaggi non elaborabili
# Le Lambda usano le SQS come event source (SQS trigger)

# Configurazione Lambda con SQS trigger
resource "aws_lambda_event_source_mapping" "inventario" {
  event_source_arn = aws_sqs_queue.inventario.arn
  function_name    = aws_lambda_function.inventario_handler.arn
  batch_size       = 10         # processa 10 messaggi alla volta
  enabled          = true

  # Bisection on error: in caso di errore batch, divide il batch a meta
  # per identificare il messaggio problematico (evita il poison pill)
  bisect_batch_on_function_error = true

  # Finestra di aggregazione (utile per batch processing)
  maximum_batching_window_in_seconds = 5
}

EventBridge + SQS: 両方の長所

多くのアーキテクチャでは、EventBridge と SQS は補完的です。 EventBridge はインテリジェントなルーティングを行い、SQS はバッファリングと負荷分散を行います。 イベントは EventBridge に到着し、適切な SQS キューにルーティングされます。 そしてコンシューマー Lambda は、再試行と DLQ を使用してキューからそれを処理します。

# EventBridge --> SQS (con transform di input opzionale)
resource "aws_cloudwatch_event_target" "ordini_to_sqs" {
  rule           = aws_cloudwatch_event_rule.ordini_vip.name
  event_bus_name = aws_cloudwatch_event_bus.mioapp.name
  arn            = aws_sqs_queue.vip_orders.arn

  # Input transformer: ristruttura il payload prima di inviarlo a SQS
  # Utile per estrarre solo i campi necessari
  input_transformer {
    input_paths = {
      ordineId  = "$.detail.ordineId"
      clienteId = "$.detail.clienteId"
      totale    = "$.detail.totale"
    }
    input_template = <<-EOF
    {
      "ordineId": "<ordineId>",
      "clienteId": "<clienteId>",
      "totale": "<totale>",
      "processato_da": "eventbridge-vip-rule"
    }
    EOF
  }
}

シリーズの次のステップ

  • 第 8 条 – デッドレターキューと回復力: 正しい構成 SQS、SNS、および EventBridge の DLQ は、メッセージ損失を回避するために重要です。 可視性タイムアウト、maxReceiveCount、および再処理パターン。

他シリーズとの連携

  • AWS EventBridge (第 6 条): イベントパターンの詳細な分析、 スキーマ レジストリとイベント アーカイブ、すべての EventBridge 構成の詳細。
  • Apache Kafka (シリーズ 38): オンプレミスまたは非常に高スループットのユースケース向け (>1,000 万 msg/s)、Kafka は SQS/SNS よりも優れています。選択はクラウドプロバイダーによって異なりますが、 スループットとイベント再生の必要性によって異なります。