← AWSサービスの内部原理 コース
15. トランザクションの内部 — prepareとcommitの2段階書き込み
条件付き書き込みを複数アイテムへ拡張したDynamoDBトランザクションの仕組みを、prepare/commitの2段階書き込みを軸に図で追っていきます。
① なぜトランザクションが要るのか — 単一アイテムの限界
口座A−1万円
アイテム1口座B+1万円
アイテム21つのトランザクションに束ねる
TransactWriteItems条件付き書き込みの複数アイテム版
結果は2通りだけ
全部成功
全部失敗
片方だけ成功起こらない(お金が消えない)
- 『結果整合性とアトミックカウンター』の条件付き書き込みは「読んでから書くまでの改変検査」を単一アイテムで行う仕組みだった
- TransactGetItems は読み取り側のトランザクション版
条件付き書き込みは単一アイテムの競合しか守れない。送金のように複数アイテムを動かす処理は、TransactWriteItems / TransactGetItems で「全成功か全失敗(all-or-nothing)」にする。
② 1トランザクションに詰められる量 — 公式の上限
最大100アクション
最大100アイテム同一アカウント・同一リージョン内の1つ以上のテーブル
合計4MBまでトランザクション内アイテムの合計サイズ
さらに禁止事項
同じアイテムを複数アクションで指定 → NG例: 同一アイテムへの ConditionCheck + Update は同居不可
上限があるのは、後述の2段階書き込みを短時間で調停しきる必要があるから。公式も「分割できるトランザクションは分割せよ。単純なほど高スループットで成功しやすい」としている。
③ 内部の仕組み — prepare と commit の2段階書き込み
TransactWriteItems 受付対象: 全アイテム
1回目の下位write
prepare(準備)条件成立・競合の有無を全アイテムで検査
全アイテムOKのときだけ
commit(確定)2回目の下位writeで変更を実反映
だからコストは
キャパシティ消費が通常の2倍例: 500Bのアイテム×3個を毎秒1回 → 1アイテム2WCU(準備1+確定1)= 計6WCU
- 公式: 準備用と確定用の2回の下位read/writeはCloudWatchメトリクスで見える
- 条件不成立などでキャンセルされても、試みた分のキャパシティは消費される
DynamoDBは全アイテムに読み書きを2回ずつ行う。1回目 prepare で条件成立・競合の有無を全アイテムで確かめ、すべて揃って初めて2回目 commit で変更を反映する(2フェーズコミットの考え方)。
④ 競合検出 — 進行中トランザクションに触ると弾かれる
進行中の TransactWriteItemsアイテムXを処理中
同じアイテムXに触ると
別の TransactWriteItems / TransactGetItems→ TransactionCanceledException
単発の PutItem / UpdateItem / DeleteItem→ TransactionConflictException
この制御が保証するもの
直列化可能(serializable)分離同時操作の結果 = 順番に1つずつ実行したのと同じ。最も強い分離
- 条件不成立なら CancellationReasons に ConditionalCheckFailed が入る
- 冪等性: ClientRequestToken を付ければ二重送信しても変更は一度だけ適用(完了後10分間有効、過ぎると新規要求扱い)
進行中の TransactWriteItems が触っているアイテムに他の操作が触ると例外で弾かれる。SDKは TransactionCanceledException を自動リトライせず、CancellationReasons(アイテム順)で「どれが・なぜ」落ちたか特定できる。
⑤ ACIDの境界 — 保証は同期的な本体まで、伝播先は非同期
トランザクション本体同期・ACID保証あり
完了後、非同期・段階的に伝播(原子性なし)
GSI影の別テーブル
Streamsレコードが別々に現れ、他Txと混ざりうる
バックアップ / PITRエクスポート伝播途中だと直近Txの変更が一部しか含まれないことも
グローバルテーブルの場合
ACID保証は書き込みAPIを呼んだリージョン内のみ他リージョンへはコミット後に複製 → 部分完了状態が観測されうる
- 公式: Stream消費側はトランザクションのアトミック性や順序を仮定してはならない
- 変更後のアイテム群を「全部か何もないか」のスナップショットで読みたいときは、通常読み取りではなく TransactGetItems を使う
ACID保証が及ぶのはトランザクションの同期的な本体だけ。完了後の GSI・Streams・バックアップへの伝播は非同期・段階的で、そこでは原子性は保証されない。