EventBridge の新カスタムバスは SNS/SQS FIFO を置き換えられるか

2026-09-24 に GA した EventBridge の enhanced custom event bus(eventsv2)を、outbox + SNS/SQS FIFO で組んだイベント基盤の実測要件と突き合わせて比較する。順序・重複排除の意味論は同型だった。それでも今は乗り換えない、という結論とその理由。

はじめに

検証用のマイクロサービス基盤で、サービス間のイベント配送を outbox + relay + SNS FIFO → SQS FIFO で組んでいます。業務データと同一トランザクションで outbox に書き、relay がポーリングして SNS FIFO へ publish、受け手はサービスごとの SQS FIFO キューを購読する、教科書どおりの構成です。

そこへ 2026-09-24、EventBridge に大型アップデートが来ました。enhanced custom event bus。順序保証・重複排除・リプレイをバス本体が持つという、いままで「EventBridge は順序を保証しないので FIFO が要るなら SNS/SQS」と言われてきた前提を崩す内容です。

このバスは SNS/SQS FIFO を置き換えられるのか。実測済みの要件を物差しにして仕様を突き合わせました。結論を先に書くと「意味論は完全に満たす。それでも今は乗り換えない」です。

前提: 何が要件か

比較の物差しは、既に動いているイベント基盤で実測してきた性質です。抽象的な機能比較ではなく「うちの設計が成立するか」だけを見ます。

要件現行(SNS/SQS FIFO)での実現
集約内の順序保証MessageGroupId = 集約ID(例 photo:123)
バス側の重複排除MessageDeduplicationId = イベントID(5分窓)
at-least-once + 受信側冪等配送は at-least-once 前提、受信側の inbox テーブルが主たる防御
再生の正は outboxSQS は replay できないため、outbox から再 publish する管理コマンドを持つ
ローカル代替LocalStack(FIFO の順序・重複排除・可視性タイムアウト・DLQ・ファンアウトを実測して採用)

現行構成を図にするとこうです。

受け手サービスA

送り手サービス

同一 tx

Publish

MessageGroupId=集約ID

DeduplicationId=イベントID

同一 tx

usecase

業務データ + outbox を

同一トランザクションで確定

outbox

再生の正

relay

未送信をポーリング

SNS FIFO

トピック

SQS FIFO

受け手Aのキュー

SQS FIFO

受け手Bのキュー

consumer

inbox

重複排除の主防御

受け手B(同構造)

ポイントは物差しの最後の 2 つです。「再生の正はバスに置かない」「ローカルで同じ経路を組めること」は、機能表には出てこないが設計の成立条件になっている要件です。

enhanced custom event bus とは

従来の EventBridge(ルール + ターゲット)とは別物の新 API 系です。サービス名前空間からして違います。

モデルを図にするとこうです。SNS の「トピック + サブスクリプション」に似ていますが、フィルタ・変換・リトライ・DLQ・開始位置がぜんぶ Subscriber という 1 リソースに寄っているのが特徴です。

購読側アカウントB

購読側アカウントA(egress 課金)

event-busv2(retention 1〜365日)

重複排除

5分窓 → DEDUPLICATED

イベントログ

POINT_IN_TIME から再読可

発行者

PutEvents / PutRawEvents

EventGroupId・DeduplicationId

Subscriber (FIFO)

filter + JSONata 変換

retry + DLQ + 開始位置

Subscriber (標準)

ターゲット

SQS / Lambda / HTTP /

Kinesis / SFn / aws-sdk 直

ターゲット

物差しとの突き合わせ

順序: EventGroupId で同型

PutRawEvents のエントリに SystemMetadata.EventGroupId(1〜128字)を載せ、Subscriber を --type FIFO で作ると、グループ単位で発行順どおりに配送されます。スループットはグループ数でスケールする、という説明まで含めて SQS FIFO の MessageGroupId と同じ意味論です。

判定: ✓ 同型。

重複排除: 5分窓まで同じ

SystemMetadata.DeduplicationId を明示するか、コンテンツハッシュによる自動判定。窓は 5分。重複した publish は DEDUPLICATED という成功コードで返ります。

窓の長さまで SQS FIFO と同じなので、SQS FIFO で踏んだ罠もそのまま持ち込まれます。うちでは「outbox からの意図した再生(republish)が、5分以内のイベントをバスの重複排除に黙って落とされて空振りする」事故を実測しており、再生時だけ DeduplicationId を実行ごとの値に変える迂回を入れています。enhanced bus に乗り換えてもこの迂回はそのまま必要です。

ドキュメント側も「重複排除は producer リトライ対策であり exactly-once ではない」と明言しています。

判定: ✓ 同型(罠まで同型)。

配送保証: inbox 前提は変わらない

配送は push 型で、RetryPolicy(既定 5 回 / 300 秒)を使い切ると OnFailureConfiguration の SQS キュー(DLQ)へ落ちます。exactly-once は謳われていないので、受信側の inbox(処理済みイベントIDの永続化)が主たる防御という設計はそのまま活きます。

1 つ注意があり、FIFO グループ内で配送に失敗したイベントは、リトライしている間そのグループの後続をブロックします。これは自前 relay の「失敗した集約の後続をスキップする」判断と同じ性質がバス側にもある、ということです。順序付き Subscriber はリトライ窓を短めにして DLQ と組み合わせるのが定石になりそうです。

判定: ✓ 前提変わらず。

再生: バスにも replay があるが、正は outbox のまま

enhanced bus は 1〜365 日の retention を持ち、Subscriber を StartingPosition: POINT_IN_TIME で作ると過去のイベントから読み始められます。SQS には無かった機能で、「新規購読者の初期構築」がバス機能だけでできるようになります。

ただし、うちの設計は「再生の正は outbox テーブル」で確定させています。バスの retention は課金対象($0.08/GB-月)ですし、365 日を超える再生や「イベント設計を変えた上での再構築」はどのみち outbox からしかできません。バス replay は補助として嬉しい、程度の位置づけです。

判定: ✓ 設計変更不要(むしろ補助が増える)。

ローカル代替: ここで止まる

現時点で無し。 これが結論を決めました。

LocalStack には「EventBridge v2 provider」(PROVIDER_OVERRIDE_EVENTS=v2)がありますが、これは旧 events API の内部実装を書き直したもので、eventsv2 という新サービスとは別物です。GA から数日の API をエミュレータが追えているはずもなく、event-busv2 / Subscriber / PutRawEvents をローカルで組む手段は今のところありません。

うちはローカルエミュレータを採用するとき「検証したい経路がローカルで組めるか」を実測して決めています(LocalStack の SQS FIFO は順序・重複排除・可視性タイムアウト・DLQ・SNS ファンアウトの 5 性質を全部実測してから採用しました)。その物差しで、enhanced bus は現時点で候補になりません。

判定: ✗。

乗り換えるとしたら、差分はどれくらいか

意味論が同型なので、実は差分がとても小さいことも分かりました。想定アーキテクチャを現行と並べます。

現行: SNS FIFO

Publish

MessageGroupId

MessageDeduplicationId

relay

SNS FIFO

SQS FIFO

consumer + inbox

想定: enhanced bus(変わるのは色付きの2箇所だけ)

PutRawEvents

EventGroupId=集約ID

DeduplicationId=イベントID

relay

(送信アダプタのみ差し替え)

event-busv2

FIFO Subscriber

SqsParameters:

MessageGroupId =

&{% $events.SystemMetadata.EventGroupId %&}

SQS FIFO

consumer + inbox

(無変更)

Subscriber のターゲットには SQS を指定でき、JSONata で EventGroupId を SQS FIFO の MessageGroupId に写せます。つまり 受信側(SQS ポーリング + inbox)は 1 行も変えず、送信アダプタ 1 つと IaC の差し替えで済む。SNS FIFO が座っていた場所に EventBridge が入るだけです。

送信側インターフェースを Bus interface { Publish(ctx, Event) error } の 1 メソッドに絞ってあったことが、この見積もりの小ささに効いています。バスの乗り換え検討が「アダプタ 1 実装ぶん」で見積もれるのは、差し込み口を薄く保ってきた配当です。

細かい落とし穴メモ

ドキュメントと解説記事から拾った、ハマりそうな点を記録しておきます。

結論

観点判定
順序・重複排除の意味論SNS/SQS FIFO と同型(5分窓・グループブロックの性質まで同じ)
移行コスト送信アダプタ 1 つ + IaC。受信側無変更
ローカル代替現時点で無し
今の判断乗り換えない。ただし「FIFO の代替にならない」からではない

「EventBridge は順序を保証しないから FIFO 用途では候補外」という長年の前提は、2026-09-24 で崩れました。機能面ではもう置き換えられます。

それでも今は乗り換えません。理由は機能ではなく開発の前提です。ローカルで同じ経路を組めないバスは、クラウド費用ゼロでローカル一気通貫を回す開発スタイルと両立しない。LocalStack が eventsv2 に対応した時点で、このバランスは変わります。

一方、プロダクションの文脈では別の計算が働きます。per-GB 課金(旧来の $1/100万件と比べて小さいイベントを大量に流すほど有利)と、発行側・購読側の課金分離(チーム別チャージバックがそのまま成立する)は、複数チームでバスを共有する組織ほど効きます。「順序が要るから SNS/SQS FIFO」で思考停止せず、実機検証のタイミングで両方を同じ物差しで測る予定です。

参考

← Back to all posts