Outbox パターン
DB の変更とイベント発行を 1 つのトランザクションで保証するメッセージング信頼性パターン
設計パターンイベント駆動
Outbox パターンとは
Outbox パターンは、DB の変更とイベント発行を 1 つのトランザクションで保証するパターンである。DB に書き込んだがイベントが発行されない (またはその逆) という不整合を防ぐ。
問題: 二重書き込み
二重書き込みが起きる典型的な例を図で示す。
❌ DB 書き込み + イベント発行が別トランザクション:
1. DynamoDB に注文を保存 → 成功
2. EventBridge にイベント発行 → 失敗
→ 注文は保存されたがイベントが失われる
Outbox パターンの仕組み
DB への書き込みとイベント発行を原子的に行うため、ビジネスデータと Outbox レコードを同一トランザクション (DynamoDB の TransactWrite) で書き込む。その後、DynamoDB Streams が Outbox の変更を検知し、Lambda がイベントを EventBridge に発行する。DB 書き込みが成功すればイベントも必ず発行される。
1. DynamoDB に注文 + Outbox レコードを TransactWrite
2. DynamoDB Streams が Outbox の変更を検知
3. Lambda が Outbox レコードを読み取り、EventBridge に発行
→ DB 書き込みとイベント発行が原子的
DynamoDB での実装
DynamoDB での実装のコード例を示す。
await db.transactWrite({
TransactItems: [
{ Put: { TableName: 'orders', Item: { PK: `ORDER#${id}`, ...order } } },
{ Put: { TableName: 'outbox', Item: {
PK: `OUTBOX#${id}`,
eventType: 'OrderCreated',
payload: JSON.stringify(order),
createdAt: Date.now(),
} } },
],
});
// 両方が成功 or 両方が失敗 (原子性)
Outbox vs 直接イベント発行
Outbox と直接イベント発行の違いを以下にまとめる。
| 観点 | 直接発行 | Outbox |
|---|---|---|
| 原子性 | ❌ (二重書き込み) | ✅ (1 トランザクション) |
| 複雑さ | 低い | 中 |
| 遅延 | 低い | やや高い (Streams 経由) |
| 信頼性 | 低い | 高い |
いつ使うか
いつ使うかの判断基準を以下にまとめる。
| ケース | 推奨 |
|---|---|
| イベントの欠損が許容できない | ✅ Outbox |
| 最終的に整合すれば十分 | 直接発行 + リトライ |
| 金融取引、注文処理 | ✅ Outbox |
Outbox パターンの背景や設計思想は関連書籍に詳しい。
この記事は役に立ちましたか?
関連用語
イベントソーシング
状態の変更をイベントとして記録し、イベントの再生で現在の状態を復元する設計パターン
Change Data Capture
データベースの変更をリアルタイムに検出し、下流システムに伝播させるデータ統合パターン
冪等性
同じ操作を何度実行しても結果が変わらない性質で、分散システムの信頼性を支える
トランザクショナルアウトボックス
データベースへの書き込みとイベント発行を原子的に行うための分散システムパターン
イベント駆動アーキテクチャ
イベントの発行と購読を中心にシステムを構成し、サービス間の疎結合と非同期処理を実現するアーキテクチャスタイル
ライトアンプリフィケーション
データベースへの 1 回の論理的な書き込みが、内部的に複数回の物理的な書き込みを引き起こす現象