# DynamoDB Global Tables × マルチリージョン × 災害復旧(DR) 完全ガイド（2026年版）：MREC/MRSCの整合性、競合解決、RTO/RPO設計、PITR、コスト

> DynamoDB Global Tablesによるマルチアクティブなマルチリージョン分散を、AWS公式仕様に忠実に解説。結果整合(MREC)とマルチリージョン強整合(MRSC)の違いと選び方、last-writer-wins競合解決、RTO/RPOとフェイルオーバー、PITR(35日)とバックアップ、複製書き込みユニットのコストまで、Terraform/TypeScriptの実コードでDR設計を体系化します。

- 公開日: 2026-06-25
- 著者: 友田 陽大
- タグ: AWS, DynamoDB, マルチリージョン, DR, アーキテクチャ設計, Terraform, サーバーレス
- URL: https://tomodahinata.com/blog/dynamodb-global-tables-multi-region-disaster-recovery-guide

## 要点

- 可用性とグローバル性能は、アプリの努力ではなくレプリケーションの設計で買う。ただし整合性モデルの理解が前提。Global Tablesはマルチアクティブで、どのレプリカも読み書きできる
- 整合性は2モード。既定のMREC（結果整合・非同期・通常1秒以内・last-writer-wins・RPOは複製遅延ぶん＝数秒）と、2025年6月導入のMRSC（同期・強整合・RPOゼロだが書き込みレイテンシは増える）
- MRSCは正確に3リージョン構成（3レプリカ or 2レプリカ＋witness）、特定のリージョンセット内限定、TTL/LSI/トランザクション非対応、空のテーブルからのみ作成可。万能ではない
- DRの土台は単一リージョンでも3AZ自動複製（SLA 99.99%）。Global Tablesでマルチリージョン化するとSLAは99.999%へ。RRはアプリ側のリージョンルーティングとフェイルオーバーで実現する
- コストは複製書き込みユニット(rWRU/rWCU)＝レプリカのリージョン数ぶん書き込み課金＋リージョン×ストレージ＋クロスリージョン転送。witnessはrWRU・ストレージ・転送課金なし

---

「DBを冗長化したい」「リージョン障害でも止めたくない」——この要件に対して、アプリケーション側でレプリケーションキューを組んだり、二重書き込みを手で実装したりするのは、ほぼ常に間違いです。

DynamoDB Global Tablesの核心は、**可用性とグローバル性能を「アプリの努力」ではなく「レプリケーションの設計」で買える**ことにあります。AWSがマルチリージョンの非同期/同期レプリケーションをフルマネージドで提供するので、アプリは自分のリージョンのローカルエンドポイントに読み書きするだけでいい。**ただし1つだけ、設計者が必ず理解しておくべき前提があります。整合性モデルです。** ここを誤解したまま導入すると、「更新が静かに消える」「強整合のつもりが古い値を読む」という、再現しにくく深刻な事故を抱え込みます。

本記事は、私が**サーバーレス（Lambda + DynamoDB）のマルチテナント決済プラットフォームの信頼性レイヤー**を設計・主導し、**本番稼働中の二重課金0件**を維持してきた経験をベースに、Global Tablesとマルチリージョンによる**DR（災害復旧）設計**だけを体系化したものです。データモデリングや冪等性の設計は[シングルテーブル設計＆本番信頼性パターンガイド](/blog/dynamodb-single-table-design-reliability-idempotency-patterns)に、キャパシティとコストの基礎は[キャパシティ・コスト・性能設計ガイド](/blog/dynamodb-capacity-cost-performance-on-demand-vs-provisioned-guide)に譲ります。本記事はそれらと相補的に、**「複数リージョンで、どう止めずに、いくらで動かすか」**に絞ります。

すべての仕様・上限値はAWS公式ドキュメント（2026年6月時点）に照合しています。料金はリージョン・時期で変わるため、金額は必ず[公式料金ページ](https://aws.amazon.com/dynamodb/pricing/)で確認してください。

---

## 1. Global Tablesの仕組み：マルチアクティブな自動レプリケーション

公式の定義はこうです。

> Amazon DynamoDB global tables is a fully managed, multi-Region, and multi-active database feature that provides easy to use data replication and fast local read and write performance for globally scaled applications.（Global Tablesは、フルマネージド・マルチリージョン・マルチアクティブなデータベース機能で、グローバル規模のアプリケーションに、容易なデータレプリケーションと高速なローカル読み書き性能を提供する）

ここから読み取るべき性質を分解します。

- **グローバルテーブル＝2つ以上のリージョンにまたがるレプリカテーブルの集合。** 1つのリージョンに置けるレプリカは1つだけ。全レプリカは**同じテーブル名・同じ主キースキーマ・同じアイテムデータ**を共有する。
- **マルチアクティブ（active-active）。** どのレプリカも読み取り「と」書き込みを受け付ける。「プライマリ1つ＋リードレプリカ」ではない。**どのリージョンの視点でも対等**。
- **自動レプリケーション。** あるリージョンのレプリカに書き込むと、DynamoDBが他の全レプリカへ自動で複製する。アプリ側のレプリケーション実装は不要。
- **アプリ変更不要。** Global Tablesは既存のDynamoDB APIをそのまま使う。**DynamoDBにグローバルエンドポイントは存在せず、すべてのリクエストはリージョナルエンドポイント宛て**になる。アプリは「自分のリージョンのローカルエンドポイント」に話しかける。

この最後の点が設計上きわめて重要です。公式のベストプラクティスは明確です。

> Calls to DynamoDB should not go across Regions.（DynamoDBへの呼び出しはリージョンをまたぐべきではない）

つまり、東京のアプリは東京のDynamoDBレプリカだけを叩く。リージョンに問題が出たら、**エンドユーザーのトラフィックを別リージョンのアプリスタックごと切り替える**。Global Tablesは「全リージョンのアプリが同じデータにアクセスできる」状態を保証する土台であって、**フェイルオーバーの「判断とルーティング」はアプリ／インフラ側の責務**です（4章で詳述）。

### 可用性：単一リージョン99.99% → マルチリージョン99.999%

公式の数値です。

| 構成 | 設計上の可用性SLA |
| --- | --- |
| 単一リージョンテーブル | 99.99% |
| マルチリージョン（Global Tables） | **99.999%** |

単一リージョンでも、DynamoDBは**データを1リージョン内の3つのアベイラビリティゾーン(AZ)へ自動複製**しており、AZ障害には既定で耐えます。Global Tablesが買い足すのは、その上の**「リージョン障害への耐性」**です。

---

## 2. 整合性モデル：MREC vs MRSC（ここが設計の心臓部）

Global Tablesを使うなら、**最初に1つだけ重い意思決定**があります。整合性モード(consistency mode)です。

> Global tables support two consistency modes: multi-Region eventual consistency (MREC) and multi-Region strong consistency (MRSC).

重要な制約を先に押さえます。

- 指定しなければ**既定はMREC**（結果整合）。
- **1つのグローバルテーブル内に、異なる整合性モードのレプリカは混在できない。**
- **作成後にモードは変更できない。** 後から「やっぱり強整合に」はできない。最初の設計判断が固定される。

### 2.1 MREC（マルチリージョン結果整合）— 既定・非同期・last-writer-wins

MRECは、アイテムの変更を他の全レプリカへ**非同期に複製**します。公式いわく**「通常1秒以内（typically within a second or less）」**で伝播します。書き込みはローカルリージョンで完結して即座に返るため、**書き込みレイテンシが低い**のが利点です。

問題は競合です。**同じアイテムが複数リージョンでほぼ同時に更新された場合**、どうなるか。

> If the same item is modified in multiple Regions simultaneously, DynamoDB will resolve the conflict by using the modification with the latest internal timestamp on a per-item basis, referred to as a "last writer wins" conflict resolution method.

**last-writer-wins（後勝ち）**で解決されます。アイテムごとに内部タイムスタンプを持ち、**タイムスタンプが大きい方が勝ち、負けた方の更新は静かに破棄**されます。公式の表現がそのまま事故の警告になっています。

> The first operation "loses" to the second operation. These conflicts aren't recorded in CloudWatch or AWS CloudTrail.

つまり**競合による更新喪失は、CloudWatchにもCloudTrailにも記録されません**。気づけないのです。これがMRECで最も深刻な落とし穴で、7章で対策を述べます。

MRECの強整合読み取りには注意点があります。`ConsistentRead: true` を付けても、

> Strongly consistent read operations return the latest version of an item if that item was last updated in the Region where the read occurred, but may return stale data if the item was last updated in a different Region.

**「同じリージョンで最後に更新されたなら最新を返すが、別リージョンで更新されたものは古い値を返しうる」**。MRECの「強整合」はあくまで**ローカルリージョン内**の話で、グローバルには強整合ではありません。

### 2.2 MRSC（マルチリージョン強整合）— 2025年6月導入・同期・RPOゼロ

MRSCは比較的新しいモードです（公式の設計ガイドに「introduced in June 2025」と明記）。

> Item changes in an MRSC global table replica are synchronously replicated to at least one other Region before the write operation returns a successful response.

書き込みは、**成功を返す前に少なくとも1つの他リージョンへ同期複製**されます。だから**どのレプリカで強整合読み取りしても常に最新**を返し、条件付き書き込みも**常に最新版に対して評価**されます。代償は**書き込みと強整合読み取りのレイテンシ増**（クロスリージョン通信が入るため）です。

MRSCには固有の制約が多く、ここを知らずに選ぶと詰みます。

- **正確に3リージョン構成。** 「3レプリカ」または「2レプリカ＋1 witness」のいずれか。**レプリカの追加削除は不可**（2レプリカ＋witnessのまま、後からレプリカを足せない）。
- **witness（証人）** は最新データを保持するがwitnessに対して読み書きはできない。full replicaの代替で可用性のクォーラムを支える。**witnessはストレージ・書き込みコストがかからない**。
- **リージョンセット内限定。** US（バージニア北部/オハイオ/オレゴン）、EU（アイルランド/ロンドン/パリ/フランクフルト）、AP（東京/ソウル/大阪）。**セットをまたげない**（例：USとEUを混在させたMRSCは作れない）。
- **空のテーブルからのみ作成可。** 既存データを持つ単一リージョンテーブルをMRSCに変換することはできない。
- **TTL非対応・LSI非対応・トランザクション(TransactWriteItems/TransactGetItems)非対応。**
- 競合は後勝ちではなく、**同時更新は `ReplicatedWriteConflictException` で失敗**する（リトライ可能）。LWWによる暗黙の更新喪失が起きない代わりに、競合をアプリが明示的にハンドリングする。

### 2.3 比較表と選び方

| 観点 | MREC（既定） | MRSC（2025年6月〜） |
| --- | --- | --- |
| レプリケーション | 非同期（通常1秒以内） | 同期（成功前に他1リージョン以上へ複製） |
| グローバル強整合読み取り | 不可（別リージョン更新は古い値もありうる） | **常に最新**を返す |
| 競合解決 | last-writer-wins（負けは静かに消失） | `ReplicatedWriteConflictException`（明示的失敗・リトライ） |
| 書き込みレイテンシ | 低い | 高い（クロスリージョン往復ぶん） |
| **RPO** | 複製遅延ぶん（通常数秒、>0） | **ゼロ** |
| リージョン構成 | 任意の数・任意のリージョン（パーティション内） | **正確に3**・リージョンセット内・追加削除不可 |
| TTL / LSI / トランザクション | TTL可・トランザクションはリージョン内のみ原子 | **すべて非対応** |
| Streams | 既定で有効（複製に使用） | 既定無効（複製に未使用・任意で有効化可） |
| 既存テーブルからの変換 | 既存テーブルにレプリカ追加でOK | **空テーブルからのみ** |

公式の選び方の基準は明快です。

> The key criteria for choosing a multi-Region consistency mode is whether your application prioritizes lower latency writes and strongly consistent reads, or prioritizes global strong consistency.

- **MRECを使うべき:** 別リージョン更新が強整合読み取りで一時的に古く見えることを許容できる／書き込みと強整合読み取りのレイテンシを優先したい／**RPO > 0 を許容できる**。
- **MRSCを使うべき:** 複数リージョンにまたがる**グローバル強整合読み取り**が必要／グローバル整合性をレイテンシより優先する／**RPOゼロが必須**。

私の率直な意見を述べます。**多くのワークロードでは、まずMRECで十分**です。MRSCは「3リージョン固定・リージョンセット限定・TTL/LSI/トランザクション不可・空テーブルから」という制約が重く、これらが要件に刺さらないなら採用コストが見合いません。**「お金や在庫など、グローバルに同時更新されうる単一アイテムを、複数リージョンから強整合で更新する」**という限られたケースでのみMRSCの価値が出ます。それ以外は、**MREC＋アプリ側のリージョンアフィニティ設計**（後述）の方が、安く・速く・柔軟です。

そして、もし**「全部のデータを1リージョンで強整合に読み書きできれば十分」**なら——そもそもGlobal Tablesは要らず、**単一リージョン＋強整合読み取り**が最もシンプルで安い、という選択肢を常に天秤にかけるべきです。

---

## 3. ユースケース：低レイテンシ・地理冗長・DR

公式が挙げるGlobal Tables（MREC）の主な価値は3つです。

| ユースケース | 内容 |
| --- | --- |
| 低レイテンシな読み取り | データのコピーをエンドユーザーの近くに置き、読み取りのネットワークレイテンシを下げる |
| 低レイテンシな書き込み | 近いリージョンに書いて書き込みレイテンシを下げる（ただし**競合しないようルーティングを慎重に**） |
| シームレスなリージョン移行 | 新リージョンを追加→旧リージョンを削除、でデータ層を**無停止**で移設できる |

そしてMREC・MRSC共通の価値が、本記事の主題です。

> Increased resiliency and disaster recovery. If a Region has degraded performance or a full outage, you can evacuate it.

**リージョンが劣化／全断したら、そのリージョンを"退避(evacuate)"できる。** MRECなら**RPO・RTOは秒単位**、MRSCなら**RPOゼロ**。これがGlobal TablesによるDRの本質です。「バックアップから復元する」DRと違い、**最初から全リージョンに鮮度の高いデータがある**ので、復旧とは「復元」ではなく「トラフィックの付け替え」になります。

> 注：低レイテンシ「書き込み」は諸刃の剣です。複数リージョンから同じアイテムに書くと、MRECではLWW更新喪失、MRSCでは競合例外が起きます。**書き込みのルーティング設計（どのアイテムをどのリージョンが書くか）がDR設計と不可分**である、という点を7章で深掘りします。

---

## 4. DR設計：RTO/RPOと、3つの復旧手段の使い分け

DR設計は、**RTO（目標復旧時間）とRPO（目標復旧時点）を要件として先に決め**、それを満たす最小コストの手段を選ぶ作業です。DynamoDBには階層の異なる3つの守りがあります。

| 守りの層 | 障害範囲 | 仕組み | RPO | RTO |
| --- | --- | --- | --- | --- |
| マルチAZ（**既定・無料**） | AZ障害 | 1リージョン内の**3AZへ自動複製**。設定不要 | 0 | 透過的（自動フェイルオーバー） |
| **Global Tables**（MREC） | リージョン障害 | マルチアクティブ複製。別リージョンへトラフィック退避 | 数秒（複製遅延） | 秒〜分（ルーティング切替次第） |
| **Global Tables**（MRSC） | リージョン障害 | 同期複製・強整合 | **0** | 秒〜分（同上） |
| PITR / バックアップ | 論理破壊・誤削除・ランサム | 時点復元・スナップショット。**新テーブルへ復元** | 復元時点まで巻き戻る | 復元時間（分〜時間） |

ここで設計者が混同しがちな2つの軸を、はっきり分けます。

- **Global Tables（アクティブ-アクティブ）が守るのは「インフラ障害」。** リージョンやAZが落ちても、別の生きたレプリカへ切り替えて事業を継続する。**データはリアルタイムに同期されている**。
- **PITR/バックアップが守るのは「論理障害」。** バグや誤操作、ランサムウェアで**データそのものが壊れた／消えた**場合に、健全だった時点へ巻き戻す。**Global Tablesはこれを守れない**——壊れた書き込みも、消した削除も、忠実に全レプリカへ複製してしまうからです。

**この2つは代替関係ではなく、両方必要**です。リージョン障害にはGlobal Tables、データ破壊にはPITR。DR設計でどちらか一方しか持たない構成は、片側のリスクに対して無防備です。

### フェイルオーバーとリージョンルーティング

Global Tablesは「データの可用性」は保証しますが、**「どのリージョンに繋ぐか」の判断はしてくれません**。1章で見たとおりDynamoDBにグローバルエンドポイントはなく、アプリは自分のリージョンのローカルエンドポイントを叩きます。だからDRの**RTOを決めるのは、実質的にアプリ／インフラ側のルーティング切替速度**です。

典型的な構成は、フロントを **Route 53（ヘルスチェック＋フェイルオーバールーティング）や AWS Global Accelerator** で複数リージョンのアプリスタックに分散し、リージョン障害を検知したらトラフィックを健全リージョンへ寄せる、というものです（公式の推奨リソースにも Route 53 / Global Accelerator / Application Recovery Controller が挙がっています）。アプリ側は、**自分が今いるリージョンのDynamoDBエンドポイントだけを使う**よう、リージョンを意識したクライアント生成にします。

```ts
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import { DynamoDBDocumentClient } from "@aws-sdk/lib-dynamodb";

/**
 * リージョン対応クライアント。
 * 原則：アプリは「自分が動いているリージョンのローカルエンドポイント」だけを叩く
 *       （公式：DynamoDBへの呼び出しはリージョンをまたぐべきではない）。
 * フェイルオーバーは Lambda/ECS を別リージョンで実行することで実現し、
 * クライアント側でリージョンを跨ぐリトライはしない（クロスリージョン呼び出しを避ける）。
 */
const HOME_REGION = process.env.AWS_REGION ?? "ap-northeast-1";

// SDK のリージョン解決は AWS_REGION に従うので、明示しておくと意図が明確になる
export const ddb = DynamoDBDocumentClient.from(
  new DynamoDBClient({ region: HOME_REGION }),
  { marshallOptions: { removeUndefinedValues: true } },
);

/**
 * 書き込みのリージョンアフィニティ（MRECでの競合回避）：
 * 「あるエンティティの書き込みは、常に同じ"ホームリージョン"で行う」よう
 * 上位のルーティング層（Route 53 等）で寄せるのが定石。
 * これにより同一アイテムの同時マルチリージョン更新＝LWW更新喪失を構造的に防ぐ。
 */
export function homeRegionFor(/* tenantId: string */): string {
  // 例：テナントIDのハッシュでホームリージョンを決め、書き込みを1リージョンに固定する。
  // 読み取りは任意のローカルリージョンから（低レイテンシ）。
  return HOME_REGION;
}
```

ポイントは、**フェイルオーバーをSDKのリトライで実装しない**ことです。クロスリージョン呼び出しは公式が避けよと明言する遅延要因であり、リージョン障害時に別リージョンのエンドポイントを叩きにいくクライアントは、健全時にもレイテンシとコストを悪化させます。**「アプリスタックごと別リージョンで動かし、入口のルーティングで切り替える」**のが正しい層分けです。

---

## 5. PITRとオンデマンドバックアップの使い分け

論理障害に対する守りが、PITRとオンデマンドバックアップです。両者は役割が違います。

### PITR（ポイントインタイムリカバリ）

> Point-in-time recovery (PITR) backups are fully managed by DynamoDB and provide up to 35 days of recovery points at a per second granularity.

- **最大35日**の連続バックアップを、**1秒単位の粒度**で保持。`RecoveryPeriodinDays` を **1〜35日**で短縮設定でき、短縮してもPITR料金は変わらない（料金はテーブル＋LSIのサイズ基準）。
- 有効化後は、**「現在の5分前」から設定した保持期間まで**の任意時点へ復元できる。
- **復元は必ず新しいテーブルへ**行われる。元テーブルを上書きしない。
- **性能・APIレイテンシに影響しない。**
- Global Tablesでは**各レプリカで個別にPITRを有効化**できる。復元すると**グローバルテーブルから独立した単独テーブル**になる（現行版2019.11.21なら、復元後のテーブルから新しいグローバルテーブルを作り直せる）。
- **クロスリージョン復元**も可能（別リージョンに復元先テーブルを作れる）。

### オンデマンドバックアップ

> You can use the DynamoDB on-demand backup capability to create full backups of your tables for long-term retention, and archiving for regulatory compliance needs.

- **フルバックアップ**を任意のタイミングで取得。長期保持・規制対応のアーカイブ向け。
- **本番テーブルの性能・可用性に影響しない**。数MB〜数百TBまで対応。
- すべて自動で暗号化・カタログ化される。**明示的に削除するまで保持**。
- **AWS Backup** と統合でき、AWS Backup経由なら**バックアップをリージョン間で自動複製**してさらにレジリエンスを高められる。

### 使い分け表

| 観点 | PITR | オンデマンドバックアップ |
| --- | --- | --- |
| 種類 | 連続バックアップ（時点復元） | スナップショット |
| 保持 | **最大35日**（1〜35で設定可） | 削除するまで無期限 |
| 粒度 | **1秒単位**の任意時点 | 取得した瞬間のみ |
| 主用途 | 直近の誤操作・破壊からの巻き戻し | 長期保持・規制アーカイブ・節目の固定 |
| 復元先 | 新テーブル（クロスリージョン可） | 新テーブル |

公式のGlobal Tablesベストプラクティスは、現実的な指針を示しています。

> Enabling automated backups and Point-in-Time Recovery (PITR) for one replica in a global table may be sufficient to meet your disaster recovery objectives.

**グローバルテーブルの「1つのレプリカ」でPITR／バックアップを有効化すれば、DR目標を満たすのに十分なことが多い**。全レプリカで重複して取る必要は通常ありません（PITR設定はレプリカ間で同期されない＝個別管理なので、どこで取るかを明示的に決める）。私の実務では、**直近の論理破壊にはPITR（短い保持で十分なテーブルは `RecoveryPeriodinDays` を絞る）、規制・監査用の固定点にはオンデマンドバックアップ＋AWS Backup**、という二段で設計しています。

---

## 6. コスト：複製書き込みユニットという考え方

Global Tablesのコストは、**単一リージョンと「書き込みの数え方」が変わる**点を理解すれば計算できます。読み取りやストレージの基礎は[キャパシティ・コスト・性能設計ガイド](/blog/dynamodb-capacity-cost-performance-on-demand-vs-provisioned-guide)に譲り、ここではマルチリージョン固有の差分だけを扱います。

公式の billing モデルです。単一リージョンテーブルにレプリカを足してグローバルテーブルにすると、書き込みの課金単位が変わります。

> Replicated Write Request Units (rWRUs) for on-demand capacity mode, where one rWRU per replica table is charged for each write up to 1KB

- **複製書き込みユニット（rWRU＝オンデマンド／rWCU＝プロビジョンド）** で課金される。**1KBごとの書き込みに対し、レプリカテーブル1つあたり1単位**。
- 単価は**単一リージョンの書き込みユニット（WRU/WCU）と同じ**。安くなるわけでも高くなるわけでもなく、**「リージョンの数だけ課金される」**という構造。
- **rWRU/rWCUの課金は、レプリカを持つ全リージョンで発生**する。
- これに加えて**クロスリージョンのデータ転送料**が、リージョン間複製ぶんかかる。
- **ストレージはリージョンごと**にかかる（各レプリカが全データを保持するため、実質ストレージ×レプリカ数）。
- **GSIの更新は通常のWRU/WCUで課金**される（レプリカテーブル上のGSIでも、rではなく通常単位）。
- 整合性モードによる**rWRU/rWCU単価の差はない**（MRECもMRSCも同じ）。**MRSCのwitnessは、rWRU/rWCU・ストレージ・複製のデータ転送のいずれも課金されない**。

### 公式の課金例（書き込みのみ）

公式が挙げる例を読むと、コスト構造が一目で分かります。

- **Day 1（単一リージョン）:** us-west-2 に1KBアイテムを100件書く → **100 WRU**。
- **Day 2（レプリカ追加でグローバル化）:** us-east-2 にレプリカを追加。us-west-2 に150件書くと → **us-west-2 に150 rWRU ＋ us-east-2 に150 rWRU ＝ 合計300 rWRU**。

**2リージョン構成にした瞬間、同じ150件の書き込みが「300書き込みユニット相当」**になる。これがGlobal Tablesの最大のコスト要因です。**書き込みコストはおおむねレプリカのリージョン数に比例**し、さらにクロスリージョン転送とリージョン×ストレージが乗ります。

> ざっくりした見積もり指針：「3リージョンのグローバルテーブルにすると、**書き込みコストは単一リージョンの約3倍**＋クロスリージョン転送＋ストレージ×3」。読み取りは各リージョンのローカル読み取りなので低レイテンシだが、**書き込み主体のワークロードほどマルチリージョン化のコスト増が効く**。

だからこそ、**「全テーブルを無条件にグローバル化しない」**のが鉄則です。リージョン障害で止められない・グローバルに低レイテンシが要る、と説明できるテーブルだけをGlobal Tablesにし、それ以外は単一リージョン＋（必要なら）クロスリージョンPITR復元、という線引きがコスト効率に優れます。

---

## 7. 落とし穴：LWW更新喪失・冪等性・時計・一意性・複製ラグ

Global Tablesは強力ですが、**分散の難しさが消えるわけではなく、AWSの層に移るだけ**です。設計者が引き受け続けるべき落とし穴を挙げます。

### (1) MRECのlast-writer-wins＝更新喪失（最重要）

2章のとおり、MRECでは同一アイテムへの同時マルチリージョン更新が**後勝ちで片方を静かに消し**、しかも**CloudWatch/CloudTrailに記録されない**。残高・在庫・カウンタのような**読んで増減する値を複数リージョンから書く**のは、MRECでは危険です。

対策は、公式の設計ガイドが推す**「書き込みのリージョンアフィニティ（home Region pinning）」**です。**あるエンティティの書き込みは、常に同じ1つのホームリージョンで行う**ようルーティング層で寄せる。読み取りは任意のローカルリージョンから（低レイテンシ）。こうすれば**同一アイテムが2リージョンで同時に書かれる状況そのものが起きない**ため、LWWの出番がなくなります。「マルチアクティブだから全リージョンから何でも書ける」と素朴に運用しないこと——これがMREC運用の一丁目一番地です。グローバルに同一アイテムを強整合更新せざるを得ないなら、そこは**MRSC**の出番です。

### (2) 冪等性は依然としてアプリの責務

リージョン障害でのフェイルオーバー中は、リトライと再送が増えます。Global Tablesは**冪等性を提供しません**。`attribute_not_exists` による一度きりの作成や、冪等性キー＋保存済みレスポンスといったパターンは、マルチリージョンでも変わらず必要です（[冪等性パターンの詳細](/blog/dynamodb-single-table-design-reliability-idempotency-patterns)）。**フェイルオーバーは冪等性が試される瞬間**だと考えてください。

### (3) トランザクションはリージョン内でのみ原子的（MREC）

これは見落としやすい重大仕様です。MRECでは、

> Transactional writes are not replicated as a unit across Regions, meaning only some of the writes in a transaction may be returned by read operations in other replicas at a given point in time.

**`TransactWriteItems` はそれを実行したリージョン内でのみ原子的**で、**ユニットとしてはリージョンをまたいで複製されません**。あるリージョンでトランザクションした複数アイテムは、**他リージョンでは部分適用の状態が一時的に観測されうる**。「全リージョンでトランザクションが原子的」と誤解すると、別リージョンの読み取りで中途半端な状態を拾います。MRSCに至っては**トランザクション自体が非対応**です。

### (4) 時計・タイムスタンプ

MRECのLWWは**内部タイムスタンプ**に基づきます。これはDynamoDBが管理する private system property で、アプリの `updatedAt` ではありません。とはいえ、アプリ側でバージョン番号や `updatedAt` を持って**条件付き書き込み（楽観ロック）**を併用すると、想定外の上書きを早期に検知できます。マルチリージョンでは**「ローカルの時計を信用した分散ロジック」を書かない**のが安全側です。

### (5) グローバルでの一意性

DynamoDBの一意性保証は**アイテム単位の条件付き書き込み（`attribute_not_exists`）**で成り立ちますが、MRECではこれが**リージョンローカルに評価**されます。2リージョンで「同じ新規キーを同時に作成」しようとすると、両方がローカルでは成功し、複製時にLWWで片方へ収束します（＝**一方の作成が実質失われる**）。グローバルに厳密な一意性が必要なら、**そのキーの作成を単一ホームリージョンに固定する**か、**MRSC**を使います。「ユニークなはずのIDが複製後に1件になっていた」は、MREC＋マルチリージョン書き込みの典型事故です。

### (6) 複製ラグを前提に設計する

MRECは通常1秒以内に伝播しますが、**SLAはなく**、リージョン間距離やワークロードで変動します。`ReplicationLatency` メトリクス（リージョンペアごと）を監視し、**増大したらトラフィックを別リージョンへ寄せる**運用にします。アプリは「書いた直後に別リージョンで読んで最新を期待する」設計を避け、**書いたリージョンで読む（read-your-writes をローカルで満たす）**よう、読み書きのリージョンを揃えます。

---

## 8. Terraform：マルチリージョン・グローバルテーブル（MREC）

ここまでの設計判断を、IaCに落とします。`aws_dynamodb_table` の `replica` ブロックでリージョンを追加すると、そのテーブルはグローバルテーブル（現行版2019.11.21）になります。**PITRはレプリカごと**、課金はオンデマンドにして「使った分だけ＋リージョン数ぶん」を素直にします。

```hcl
# プロバイダはリージョンごとに alias を分ける（クロスリージョン管理）
provider "aws" {
  alias  = "tokyo"
  region = "ap-northeast-1"
}

# グローバルテーブルの「定義元」リージョン。replica で他リージョンを足す。
# 公式ベストプラクティス：CloudFormation/Terraform では1つの基準リージョンに
# 全レプリカ定義を集約し、リージョン別スタックに分散させない（ドリフト回避）。
resource "aws_dynamodb_table" "app" {
  provider = aws.tokyo

  name         = "AppTable"
  billing_mode = "PAY_PER_REQUEST" # オンデマンド：rWRU で「使った分×リージョン数」課金
  hash_key     = "PK"
  range_key    = "SK"

  # マルチアクティブ複製に Streams が要る（NEW_AND_OLD_IMAGES が定石）
  stream_enabled   = true
  stream_view_type = "NEW_AND_OLD_IMAGES"

  attribute {
    name = "PK"
    type = "S"
  }
  attribute {
    name = "SK"
    type = "S"
  }

  # 大阪・オレゴンへレプリカを追加 → グローバルテーブル化（MREC）
  # PITR と削除保護はレプリカ間で同期されないので、各レプリカで明示する
  replica {
    region_name            = "ap-northeast-3" # 大阪：国内の地理冗長
    point_in_time_recovery = true
  }
  replica {
    region_name            = "us-west-2" # オレゴン：別大陸の地理冗長
    point_in_time_recovery = true
  }

  # 定義元リージョンの PITR
  point_in_time_recovery {
    enabled = true
  }

  # 本番テーブルの誤削除を止める（各レプリカで個別に有効化が必要）
  deletion_protection_enabled = true

  ttl {
    attribute_name = "expiresAt"
    enabled        = true # 注：TTL複製削除はレプリカ側で rWRU/書き込みを消費する
  }

  tags = {
    Environment = "production"
    DR          = "multi-region-mrec"
  }

  # レプリカのキャパシティはグローバルで同期されるため、
  # billing_mode やキー定義の変更は全レプリカに波及する点に注意。
  lifecycle {
    ignore_changes = [replica] # 手動でのレプリカ増減との競合を避けたい場合
  }
}
```

> 設計上の注意：MRSC は現状、`replica` ブロックの素朴な指定では表現できない制約（正確に3リージョン・リージョンセット限定・空テーブル・witness）を持ち、Terraform/コンソールでの扱いが MREC と異なります。**MRSC を採用するなら、整合性モードと3リージョン構成の制約をプロビジョニング前に必ず確認**してください（本記事のTerraformは MREC 構成です）。TTL の複製削除がレプリカ側で書き込みユニットを消費する点も、プロビジョンドなら容量見積もりに含めます。

---

## FAQ

**Q1. Global Tablesの整合性は強いですか、弱いですか？**
モード次第です。既定の**MRECは結果整合**で、変更は他リージョンへ**非同期に通常1秒以内**で伝播します（グローバルには強整合ではない）。**MRSC（2025年6月導入）は強整合**で、書き込みは成功前に他リージョンへ同期複製され、どのレプリカでも最新を返します。代わりにMRSCは書き込みレイテンシが上がり、3リージョン固定などの制約があります。

**Q2. 競合（同時更新）はどう解決されますか？**
MRECは**last-writer-wins**——内部タイムスタンプが新しい方が勝ち、**負けた更新は静かに破棄され、CloudWatch/CloudTrailにも記録されません**。これによる更新喪失を避けるには、**書き込みを単一ホームリージョンに寄せる**（リージョンアフィニティ）のが定石です。MRSCは後勝ちではなく、同時更新を **`ReplicatedWriteConflictException`** で明示的に失敗させ、リトライで解消します。

**Q3. DRのRPO/RTOはどれくらいですか？**
MRECは**RPOが複製遅延ぶん（通常数秒、ゼロではない）、RTOは秒〜分**（実際はアプリのリージョンルーティング切替速度で決まる）。MRSCは**RPOゼロ**。さらに単一リージョンでも**3AZ自動複製**でAZ障害には透過的に耐えます。論理破壊（誤削除・バグ）に対するRPO/RTOは、Global Tablesではなく**PITR/バックアップの復元**で決まります。

**Q4. PITRは何日保持できますか？オンデマンドバックアップとの違いは？**
PITRは**最大35日**、**1秒単位**の任意時点へ復元でき、保持は1〜35日で設定可能。**現在の5分前**から保持期間内まで戻せます。オンデマンドバックアップは**スナップショットで、削除するまで無期限保持**——長期保持・規制アーカイブ向け。どちらも**復元は新テーブル**に対して行われ、本番性能に影響しません。直近の事故にはPITR、節目の固定点にはバックアップ、と使い分けます。

**Q5. コストは単一リージョンの何倍になりますか？**
書き込みは**複製書き込みユニット(rWRU/rWCU)で、レプリカのリージョン数ぶん課金**されます。単価は単一リージョンと同じなので、**3リージョンなら書き込みコストは概ね3倍**＋クロスリージョン転送料＋**ストレージ×リージョン数**。読み取りは各リージョンのローカル読み取りです。整合性モードでrの単価は変わらず、**MRSCのwitnessはrWRU・ストレージ・転送いずれも無課金**です。書き込み主体のテーブルほど増分が大きいので、グローバル化は必要なテーブルだけに絞ります。

**Q6. リージョン障害のフェイルオーバーは自動ですか？**
DynamoDBの**データ層は自動で全リージョンに同期**されていますが、**「どのリージョンに繋ぐか」の切り替えは自動ではありません**。DynamoDBにグローバルエンドポイントはなく、アプリは自リージョンのローカルエンドポイントを叩きます。フェイルオーバーは**アプリスタックを別リージョンでも動かし、Route 53 / Global Accelerator 等で入口を切り替える**ことで実現します。SDKのクロスリージョンリトライで実装しないのが鉄則です。

**Q7. すべてのテーブルをGlobal Tablesにすべきですか？**
いいえ。書き込みがリージョン数ぶん課金され、ストレージもリージョン数ぶんかかるため、**コストが構造的に増えます**。「リージョン障害で止められない」「グローバルに低レイテンシが要る」と説明できるテーブルだけをグローバル化し、それ以外は単一リージョン＋必要に応じたクロスリージョンPITR復元、という線引きがコスト効率に優れます。

---

## おわりに：可用性は「設計」で買い、整合性は「理解」で守る

DynamoDBのマルチリージョン／DRは、アプリにレプリケーションを書くのではなく、**Global Tablesという設計の選択**で実現します。要点を凝縮します。

- **可用性とグローバル性能はレプリケーション設計で買う**：単一リージョンの3AZ自動複製（SLA 99.99%）の上に、Global Tablesでリージョン耐性（99.999%）を足す。
- **整合性モデルを最初に決める**：既定のMREC（結果整合・低レイテンシ・RPO数秒・LWW）か、MRSC（強整合・RPOゼロ・3リージョン固定・制約多数）。**作成後に変更不可**。
- **インフラ障害はGlobal Tables、論理障害はPITR/バックアップ**：両方必要。Global Tablesは壊れた書き込みも忠実に複製する。
- **フェイルオーバーはアプリ層の責務**：ルーティング切替がRTOを決める。クロスリージョン呼び出しはしない。
- **MRECの更新喪失をリージョンアフィニティで封じる**：同一アイテムの書き込みは単一ホームリージョンへ寄せる。グローバル強整合更新が要る箇所だけMRSC。
- **コストはリージォン数に比例**：書き込みは複製ユニットでリージョン数ぶん、ストレージもリージョン数ぶん。グローバル化は必要なテーブルに絞る。

私は、一人 × 生成AI（Claude Code）という体制で、**設計判断は人間の検証ゲートを通す**進め方を徹底し、本番二重課金0件のサーバーレス決済基盤を実装・運用してきました。整合性モデルの選定、リージョンルーティングとフェイルオーバー、RTO/RPOに基づくPITR/バックアップ設計、複製コストの見積もりまで——**DynamoDBのマルチリージョン／DR設計を、要件に合わせて一緒に詰めます。**

**マルチリージョン化・DR設計でお困りの方は、[お問い合わせ](/contact)からご相談ください。** まずは守るべきRTO/RPOと、本当にグローバル化すべきテーブルの選別から、ご一緒します。
