FOR PROFESSIONALSプロフェッショナル向け

Jコンテナとサーバーレス基盤段4設計層設計

イベント駆動の設計|冪等性・リトライ・順序と SQS・EventBridge・Step Functions の選び分け

イベント駆動の設計|冪等性・リトライ・順序と SQS・EventBridge・Step Functions の選び分け

同期の API を並べただけのシステムは、1つが遅れると全部が遅れ、1つが落ちると全部が落ちます。そこでキューやイベントバスを挟んで疎結合にするわけですが、挟んだ瞬間に新しい問いが生まれます。「同じイベントが二度届いたら」「処理できないメッセージはどこへ行くのか」「順番が入れ替わったら」「どこで止まったのかをどう追うのか」。

この記事は、イベント駆動・サーバーレスの設計で先に決める判断の軸を並べます。サービスの説明ではなく、要件が変わると選ぶものがどう変わるかを、比較表と判断の順番で示します。

この記事の結論

  • 呼び出し元が結果をその場で必要とする処理だけを同期にし、それ以外は非同期に切り出します。
  • キュー・イベントバス・イベントソースマッピングは「少なくとも1回」の配信なので、処理は冪等キーで重複に耐える形にします。
  • リトライはバックオフとジッターで間隔を空け、使い切ったものは DLQ に隔離し、直してから再処理できる経路を用意します。
  • 順序の保証は、注文ごと・利用者ごとのように範囲を絞って、SQS FIFO のメッセージグループや Kinesis のパーティションキーで持たせます。
  • 流れを1か所で管理するなら Step Functions のオーケストレーション、各サービスの独立を優先するなら EventBridge のコレオグラフィーを選び、相関 ID と X-Ray で追えるようにします。

イベント駆動の設計とは(同期と非同期をどこで分けるか)

イベント駆動の設計は、「誰が誰を待つか」を決める作業です。AWS Well-Architected のサーバーレスアプリケーションレンズは、非同期の呼び出しが応答の遅延を下げ、同期の呼び出しを重ねるとタイムアウトで再試行の余地が無くなると説明しています。分け方の基準は1つで、呼び出し元が結果をその場で必要とするかです。

注文の受付なら、在庫の引き当てまでは同期で返し、確認メールの送信やポイントの付与は非同期に切り出す、という分け方になります。メールが数秒遅れても注文は成り立ちますが、在庫の有無が分からないまま「受け付けました」とは返せません。

非同期に切り出すと決めたら、次の4つを要件として書き出します。

DECIDE BEFORE SERVICES先に決める4つ

サービス名より先に待つか・重複・順序・取り消しを決める

  1. 1.呼び出し元が結果を待つか

    その場で要る処理だけ同期。残りは非同期に切り出す

  2. 2.重複と欠落のどちらが痛いか

    少なくとも1回の配信が前提。冪等キーで重複に耐える

  3. 3.順序が要る範囲

    全体ではなく、注文ごと・利用者ごとに絞る

  4. 4.失敗したとき誰が取り消すか

    リトライ・DLQ・再処理の経路と、補償の処理

出典: AWS Well-Architected サーバーレスアプリケーションレンズ(設計原則・失敗の管理)
要件の変化 選ぶものがどう変わるか
後段が遅くても受付は止めたくない SQS で受けて流量を平準化し、後段は一定の速さで取り出す
1つのイベントを複数の処理に配りたい SNS か EventBridge でファンアウトし、受け手ごとに SQS で受ける
同じ注文の中で順番が崩れると困る SQS FIFO で注文 ID をメッセージグループにする
途中で失敗したら前の処理を取り消したい Step Functions でサガを組み、補償の処理を定義する
過去のイベントを流し直して直したい EventBridge のアーカイブとリプレイ、または Kinesis の保持期間内の再読み込み

判断の順番は、同期か非同期か → 重複と欠落のどちらを防ぐか → 順序の範囲 → 失敗の扱い → 配り方と流れの管理 → 追跡の仕方です。サービス名は5番目まで出てきません。

「少なくとも1回」をどう受け止めるか(冪等性)

イベント駆動の部品の多くは、メッセージを「少なくとも1回」届けます。SQS の標準キュー、EventBridge の配信、Lambda のイベントソースマッピング、Step Functions の非同期の Express ワークフローは、どれも同じイベントが二度届くことがあります。Lambda の公式ドキュメントも、関数のコードを冪等にすることを強く推奨しています。

重複を「起きないようにする」のではなく、「起きても結果が変わらない」ように作るのが設計の出発点です。これを冪等性と呼びます。

冪等キーで「処理済み」を覚える

冪等にする型は、イベントの中から一意な値(注文 ID・リクエスト ID)を冪等キーとして選び、処理の前に「このキーは処理済みか」を確かめ、処理済みなら前回の結果をそのまま返す、です。キーの記録には、DynamoDB の条件付き書き込み(キーが無いときだけ書く)を使うと、同時に届いた重複も1件に絞れます。

Powertools for AWS Lambda の冪等性ユーティリティは、この型を部品として提供しています。イベント全体か、JMESPath で選んだ一部をハッシュして冪等キーにし、結果を DynamoDB などの永続化層に保存し、重複とみなす期間(有効期限)を設定できます。自前で書くと抜けやすい「処理中に同じキーが来たとき」の扱いも含まれているので、まずこれを使えるかを確かめます。

重複を防ぐ仕組みの範囲を知る

SQS FIFO キューは、メッセージ重複排除 ID を使って、重複排除の間隔(公式ドキュメントでは5分)の中で同じメッセージをキューに入れません。ただしこれは「送る側の再送」を防ぐ仕組みで、受け手の処理が途中で失敗して再び受け取ったときの重複までは防ぎません。Step Functions の Standard ワークフローは、Retry を定義しない限りタスクを2回以上実行しない(exactly-once)ので、決済のような冪等でない操作の順番を管理するのに向きます。どちらも「受け手の冪等性が要らなくなる」わけではありません。

CHECK 1ここまでの確認

SQS の標準キューから Lambda で注文を処理している。同じ注文が二度処理されて在庫が二重に引かれた。設計として最初に直すべきところはどこか?

答えと解説

答え: 2. 注文 ID を冪等キーにして、処理済みなら同じ結果を返すようにする

標準キューも Lambda のイベントソースマッピングも「少なくとも1回」の配信で、重複はありえます。重複を前提に、同じイベントを何度受けても結果が変わらない処理にします。「少なくとも1回」の章を読み直してください。

リトライ・DLQ・再処理はどう組むか

失敗は2種類に分けて扱います。時間を置けば通る一時的な失敗(スロットリング・タイムアウト)と、何度やっても通らない失敗(壊れたデータ・コードの誤り)です。前者はリトライで、後者は隔離で扱います。

リトライはバックオフとジッターで間隔を空ける

一時的な失敗を即座に再試行すると、混んでいる相手をさらに混ませます。再試行の間隔を指数的に延ばし(指数バックオフ)、ばらつき(ジッター)を加えて、再試行が同じ瞬間に集中しないようにします。EventBridge はターゲットへの配信に失敗すると、指数バックオフとジッターで再試行し、再試行の回数とイベントの最大の経過時間を設定できます。Step Functions は、タスクごとに Retry で間隔とバックオフの倍率を、Catch で失敗したときの行き先を定義します。

使い切ったものは DLQ に隔離する

何度やっても通らないメッセージを再試行し続けると、後ろのメッセージまで詰まります。リトライを使い切ったものはデッドレターキュー(DLQ)に移して本流から外します。サーバーレスアプリケーションレンズも、失敗した非同期の処理を DLQ で保持し、調べ、再試行することを挙げています。

入口 失敗したとき 使い切ったものの行き先
SQS → Lambda 可視性タイムアウトの後に再び見える 受信回数の上限(maxReceiveCount)を超えたら SQS の DLQ
Lambda の非同期呼び出し Lambda 側で再試行する 失敗時の送信先(SQS・SNS など)か DLQ
EventBridge のルール 再試行ポリシーで再配信する ターゲットごとに設定した SQS の DLQ。無ければ破棄
Kinesis → Lambda 成功か期限切れまで同じバッチを再処理し、シャードの処理が止まる バッチの分割で原因の記録を絞り、失敗時の送信先へ

バッチで受ける入口では、1件の失敗でバッチ全体を再処理しないように、部分的なバッチレスポンス(ReportBatchItemFailures)で失敗した記録の ID だけを返します。

リトライと DLQ で起きやすい事故の型

  • 可視性タイムアウトが処理時間より短く、処理中のメッセージが再び見えて二重に処理される。タイムアウトは処理時間に合わせ、長い処理は途中で延長する。
  • DLQ を作ったのにアラームが無く、何週間も失敗が溜まっていた。DLQ のメッセージ数と、キューの最古のメッセージの経過時間にアラームを置く。
  • EventBridge のターゲットに DLQ を設定しておらず、再試行を使い切ったイベントが破棄されていた。

再処理の経路を先に作る

DLQ は置き場であって、直す仕組みではありません。原因を直したあと、DLQ のメッセージを元のキューへ戻す(リドライブする)手順と、戻しても重複で壊れない冪等性がそろって、初めて再処理ができます。EventBridge はアーカイブにイベントを保存し、期間を指定してリプレイできるので、ルールやターゲットの誤りを直してから流し直すことができます。

CHECK 2ここまでの確認

キューの中の1件だけが壊れていて、何度処理しても失敗し、後ろのメッセージの処理まで遅れている。この状態を防ぐ組み方はどれか?

答えと解説

答え: 1. 受信回数の上限を決め、超えたメッセージを DLQ に移して隔離する

処理できないメッセージは、受信回数の上限(maxReceiveCount)を超えたら DLQ に移して本流から外します。可視性タイムアウトを短くすると、処理中のメッセージが再び見えて重複が増えます。「リトライ・DLQ・再処理」の章を参照してください。

順序はどこまで保証すべきか

順序の保証は、範囲を広げるほど流量が落ちます。「全体の順序」ではなく「同じ注文の中の順序」のように、範囲を絞って保証するのが設計の要点です。

  • SQS FIFO キュー: 同じメッセージグループ ID のメッセージは、届いた順に1件ずつ処理されます。異なるグループどうしの順序は保証されず、そのかわり並列に処理されます。注文 ID や利用者 ID をグループにすると、順序と並列度を両立できます。
  • SNS FIFO トピック: 同じメッセージグループの中で順序を保ち、重複を配信しません。受け手は SQS FIFO キューにすると、ファンアウトしながら順序を保てます。
  • Kinesis Data Streams: パーティションキーで書き込み先のシャードが決まり、シャードの中では順番に読まれます。偏ったキーを選ぶと1つのシャードに書き込みが集中するので、デバイス ID のようにばらつきの大きい値を選びます。

順序を部品に任せられないときは、イベントに版番号や発生時刻を持たせ、受け手が「手元より古いイベントは捨てる」と判断する形にします。順序の保証が要らない処理まで FIFO にすると、グループ単位で直列になるぶん流量を失います。

SQS・SNS・EventBridge・Kinesis・Step Functions をどう選び分けるか

5つは「何を渡すか」と「誰が流れを持つか」で役割が分かれます。AWS の判断ガイドも、SQS・SNS・EventBridge を、受け手の数・振り分けの細かさ・届け方の違いで比べています。

PICK THE CHANNEL渡し方を2軸で

受け手の数と順序・再読み込みの要否で選ぶ

順序と再読み込みが要る →

SQS FIFO キュー

注文ごとの順序。メッセージグループで並列度を保つ

Kinesis Data Streams

多数が同じデータを読む。シャード内の順序と再読み込み

SQS 標準キュー

流量の平準化と後段の保護。順序は保証しない

EventBridge / SNS

中身で振り分けるなら EventBridge、高い流量の一斉配信は SNS

受け手が多い →

サービス 形 受け手 順序 向く用途
Amazon SQS キュー(受け手が取りに行く) 1つの処理(複数の作業者で分担) 標準は保証なし、FIFO はグループ内 流量の平準化、後段の保護
Amazon SNS トピック(押し出して配る) 多数 標準は保証なし、FIFO はグループ内 高い流量の一斉配信、SQS へのファンアウト
Amazon EventBridge イベントバス(ルールで振り分け) 多数 保証なし 中身での細かい振り分け、AWS サービスや SaaS のイベント、アカウント間の配信
Amazon Kinesis Data Streams ストリーム(保持して読む) 多数が同じデータを読む シャード内で順序 大量の連続データ、保持期間内の再読み込み
AWS Step Functions ワークフロー(流れを定義する) 手順ごとのサービス 定義した順 複数手順の流れ、再試行・分岐・補償、人の承認

Step Functions はメッセージの通り道ではなく、流れそのものを持つ部品です。Standard は長時間の実行と実行履歴を持ち、Express は大量で短い処理を安く回します。Express の非同期の実行は「少なくとも1回」なので、冪等な処理に向きます。

CHECK 3ここまでの確認

決済・在庫・配送の3つのサービスにまたがる注文で、途中が失敗したら前の処理を取り消したい。流れを1か所で見て監査したい場合に合う組み方はどれか?

答えと解説

答え: 2. Step Functions の Standard ワークフローで手順と補償の処理を定義するオーケストレーション

流れを1か所で定義し、実行履歴で監査したいならオーケストレーションです。Standard ワークフローは長時間の実行と履歴を持ち、Retry と Catch で失敗時に補償の処理へ進めます。「サガ」の章を見直してください。

サガ:オーケストレーションとコレオグラフィーはどう選ぶか

複数のサービスにまたがる処理では、1つのデータベースのトランザクションで全体を巻き戻せません。そこで各サービスが自分の処理を確定させ、途中が失敗したら前の処理を取り消す処理(補償トランザクション)を順に実行して整合を取ります。これがサガです。AWS Prescriptive Guidance は、サガを組む方法を2つに分けています。

SAGA TWO WAYSサガの組み方

流れを誰が説明する責任を持つかで選ぶ

オーケストレーション

Step Functions が流れを持つ

  • 手順と補償を1か所で定義Standard ワークフロー、Retry と Catch
  • 実行履歴で途中経過を追える監査と取り消しの確実さが要る流れ
  • 依存がオーケストレーターに集まるPrescriptive Guidance が挙げる課題

コレオグラフィー

各サービスがイベントを購読する

  • サービスどうしが直接依存しないEventBridge でイベントを発行・購読
  • チームごとに独立して変えられる通知や連携の追加に強い
  • 全体の流れが見えにくい相関 ID と分散トレースが前提になる
出典: AWS Prescriptive Guidance「Orchestration and choreography patterns」「Saga orchestration pattern」
  • オーケストレーション: Step Functions の Standard ワークフローが手順と補償の処理を定義します。流れがコードとして1か所にあり、実行履歴で途中経過を追えます。Prescriptive Guidance は、オーケストレーターに依存が集まる点を課題に挙げています。
  • コレオグラフィー: 各サービスがイベントを購読し、自分の担当を終えたら次のイベントを発行します。サービスどうしが直接依存しないので独立して変えられますが、全体の流れはどこにも書かれておらず、追跡の仕組みが無いと「いまどこで止まっているか」が分かりません。

選び方は、流れを誰が説明する責任を持つかです。決済のように監査と取り消しの確実さが要る流れはオーケストレーション、チームごとに独立して進化させたい通知や連携はコレオグラフィーが合います。途中で人の承認を待つ流れは、Step Functions のタスクトークンで承認が返るまで待たせます。

相関 ID と X-Ray で、どこで止まったかを追えるか

非同期にすると、1つの注文の処理が複数の関数とキューに散らばります。追えるようにする仕組みは2つです。

1つ目は相関 IDです。最初の入口で ID を発行し、イベントの本文かメッセージ属性に載せて、すべてのログにその ID を出します。ログを構造化(JSON)しておけば、CloudWatch Logs Insights で ID を指定して、散らばったログを1本の流れとして並べられます。

2つ目は AWS X-Ray の分散トレースです。X-Ray は SQS を通るメッセージを追跡でき、受け手が Lambda ならトレースの文脈が自動で引き継がれます。EventBridge も、X-Ray の SDK で計測したサービスから送られたイベントについて、トレースヘッダーで文脈を下流のターゲットへ渡します。Lambda 以外の受け手では、受け渡しを自分で計測する必要があります。Step Functions は実行ごとの履歴を持つので、オーケストレーションの側はそれ自体が追跡の記録になります。

監視では、エラー率に加えて「滞留」を見ます。キューの最古のメッセージの経過時間、DLQ のメッセージ数、ストリームの読み遅れ(Lambda の IteratorAge)は、処理が止まったことを、利用者からの問い合わせより先に教えてくれます。

この記事の軸は、どれも要件が変われば答えが変わります。選んだ理由を要件の言葉で説明する型は、次の記事で扱います。

READ ALSO — プロフェッショナル向け・段4 設計 トレードオフの考え方|「なぜそのサービスか」を根拠つきで説明する型と、Well-Architected の6本柱の使い方

参照ソース

SCOREこの記事の確認テスト

0/3問 正解

各章の「ここまでの確認」に答えると、ここに集まります。結果はこの端末のブラウザにだけ残り、サーバには送りません。

PRACTICEこの記事の論点を練習問題で確かめる

この記事が扱うサービスの問題だけを続けて解けます。練習問題は Google でログインした人が使えます(練習問題の一覧)。

HAND IT OVER人に渡すなら

一言で説明するなら

イベント駆動は、注文を受けたら伝票を棚に置き、厨房が順に取りに来る店の形に近い。伝票が二重に届いても料理を二度作らない決まりと、作れなかった伝票の置き場を先に決めておく。

前提を持たない人にそのまま渡せる記事です。「後輩に説明する」「顧客に理由を伝える」の材料として。

FAQよくある質問

SNS と EventBridge は、どちらで配信すればよいですか?

受け手に一斉に高い流量で届けたいなら SNS、イベントの中身で細かく振り分けたい・AWS のサービスや SaaS からのイベントも同じ場所で扱いたい・アーカイブから再送したいなら EventBridge が合います。公式の判断ガイド(SQS・SNS・EventBridge の選び方)が同じ観点で比べています。

冪等性はすべての処理に必要ですか?

少なくとも1回の配信を受ける処理には要ります。SQS 標準キュー・EventBridge・Lambda のイベントソースマッピング・非同期の Express ワークフローは、どれも重複がありえるからです。読み取りだけの処理や、上書きしても結果が同じ処理は、それ自体が冪等なので追加の仕組みは要りません。

Step Functions の費用はどのくらいかかりますか?

Standard と Express で課金の単位が違い、改定もあるので、ここでは数字を書きません。公式の料金ページで確認してください。設計の側では、大量で短い処理を Express に、長時間で履歴が要る処理を Standard に分けると、費用と要件が揃いやすくなります。

SAME TRACK同じ領域の記事

ECS のタスク定義を設計する|サイズ・ロール・設定の渡し方を「1つのタスクに何を持たせるか」で決める
ECS のタスク定義を設計する|サイズ・ロール・設定の渡し方を「1つのタスクに何を持たせるか」で決める 段2 構成設計
ECS のタスクが止まる・デプロイが進まないときの調べ方|停止理由・サービスイベント・サーキットブレーカーを順に見る運用
ECS のタスクが止まる・デプロイが進まないときの調べ方|停止理由・サービスイベント・サーキットブレーカーを順に見る運用 段2 構成運用
Amazon EventBridge とは何か|イベントバス・ルール・ターゲットと SNS・SQS との使い分け
Amazon EventBridge とは何か|イベントバス・ルール・ターゲットと SNS・SQS との使い分け 段2 構成とは