← AWSサービスの内部原理 コース
5. 結果整合性とアトミックカウンター — 分散の一貫性と競合状態
「複製の伝播遅延」と「並行更新の排他」——すでに学んだ2つの基礎で DynamoDB の挙動を図で追っていきましょう。
①書き込みは複数AZに複製される
書き込み成功HTTP 200 = 確実に保存済み
コピーへ伝播(わずかなラグ)
AZ-A反映済み
AZ-B反映済み
AZ-Cまだ古い
- ・コピー間の反映ラグ=結果整合性(eventually consistent)
- ・複数のコピーを持つ仕組みなら必ず生じる普遍的な性質
- ・分散システムで学んだ「複製の伝播遅延」そのもの
書き込みは複数のアベイラビリティーゾーンに複製される。コピー間の反映ラグこそが結果整合性の正体。
②読み取りは2モード
get-item(読み取り)
モードを選ぶ
結果整合性(既定)一瞬古い値が返りうる
待てば追いつく強い整合性ConsistentRead=true
最新の値を返す- ・公式の保証は「返る値が最新」という結果のみ(内部手順ではない)
- ・強い整合性はテーブルとLSIのみ。GSIとストリームでは使えない
既定は結果整合性で、伝播途中のコピーを読むと一瞬古い値が返る。強い整合性は成功した全書き込みを反映した最新値を返す。
③料金の事実は一点、そこから使い分け
多少古くてもOK例: いいね数の表示
書いた値を確実に読み返す例: 直後の読み直し
選ぶ
結果整合性半額(1x)
強い整合性2倍(2x)
公式が述べる事実は「結果整合性は半額」の一点。最新でなくてよい読み取りは安い方を選ぶ、が導ける設計判断。
④同時に書くと壊れる(競合状態)
A: 読む → 100
B: 読む → 100
各自 +1 して書き戻す
A: 101 を書く
B: 101 を書く
後の書き込みが上書き
結果: 101片方の +1 が消えた
- ・両者が同じ古い値を読むのが原因(Race Condition)
- ・OSで学んだ「同じ資源を複数が読み書きすると壊れる」と同じ構図
2つのクライアントが同じ古い値を読んでから書き戻すと、片方の増加がもう片方に上書きされて消える。
⑤アトミックカウンター:増分だけ送る
A: 「+1」だけ送る
B: 「+1」だけ送る
読み取り・加算・書き込みをサーバーに任せる
DynamoDB サーバー不可分な1操作として受信順に適用
結果: 102両方の増加が反映
- ・「すべての書き込みは受信した順に適用される」(公式)
- ・クリティカルセクションの排他をマネージドサービスが肩代わり
- ・ただし冪等ではない: 同じリクエストを2回送れば2回増える
「いくつ増やすか」だけをサーバーに伝え、サーバー側が不可分な1操作として処理する。再送で二重加算が起こりうるため、多少の誤差を許せる用途向き。
⑥厳密さが要るなら条件付き書き込み
アリス: 更新成功条件 Price=10 → 成立
Price はもう 10 ではない
ボブ: 更新は失敗条件 Price=10 → 不成立
- ・条件なしだと、後から書いたボブがアリスの更新を無自覚に上書き
- ・条件付きなら更新の取りこぼし(lost update)を防げる
- ・銀行残高のように絶対にずれてはいけない値はこちら
「現在値が10のときだけ更新」と条件を付ければ、間に他人の更新が入っていれば失敗する。結果整合性も排他も、「複製の伝播遅延」と「並行更新の排他」の2つの基礎から再導出できる。
サンプルコード(フレームワーク環境が必要なため表示のみ)
// 結果整合性読み取り(既定): 直前の書き込みが未反映のことがある。安く、少し待てば追いつく
// 強い整合性読み取り: 成功した全書き込みを反映した最新値を返す(ConsistentRead=true / 結果整合性の2倍のコスト)
aws dynamodb get-item --table-name ProductCatalog --key '{"Id":{"N":"1"}}' --consistent-read
// アトミックカウンター: 読み取り→加算→書き戻しをサーバー側の不可分な1操作にまとめる
// 受信順に適用される / 冪等ではない(再送すると二重加算)ため、多少の誤差を許せる用途向け
aws dynamodb update-item --table-name ProductCatalog --key '{"Id":{"N":"601"}}' \
--update-expression "SET Price = Price + :incr" \
--expression-attribute-values '{":incr":{"N":"5"}}'
// 条件付き書き込み: 「現在値が10のときだけ更新」。間に他人の更新が入っていれば失敗し、取りこぼしを防ぐ
aws dynamodb update-item --table-name ProductCatalog --key '{"Id":{"N":"1"}}' \
--update-expression "SET Price = :newval" \
--condition-expression "Price = :currval" \
--expression-attribute-values '{":newval":{"N":"8"},":currval":{"N":"10"}}'