ストーリー
マルチリージョンのパターン
// 3つのマルチリージョンパターン
const MULTI_REGION_PATTERNS = {
activePassive: {
name: "Active-Passive (DR)",
description: "1リージョンがActive、もう1つがスタンバイ",
dataFlow: "Active → 非同期レプリケーション → Passive",
failover: "手動 or 自動フェイルオーバー(数分〜数十分)",
consistency: "非同期レプリケーションによるデータロスの可能性",
cost: "低〜中(Passiveはスタンバイ)",
useCase: "DR要件はあるがコストを抑えたい場合",
},
activeActive: {
name: "Active-Active",
description: "複数リージョンが同時にトラフィックを処理",
dataFlow: "双方向レプリケーション",
failover: "即座(DNSルーティングで切り替え)",
consistency: "競合解決が必要(CRDTやLast Write Wins)",
cost: "高(全リージョンがフル稼働)",
useCase: "グローバルサービス、最高可用性",
},
readLocalWriteGlobal: {
name: "Read Local, Write Global",
description: "読み取りは最寄りリージョン、書き込みはプライマリリージョン",
dataFlow: "Write → Primary → 非同期レプリカ → ローカル読み取り",
failover: "読み取りは即座、書き込みはフェイルオーバー",
consistency: "結果整合性(読み取り時に古いデータの可能性)",
cost: "中",
useCase: "読み取りヘビーなサービス(コンテンツ配信等)",
},
};
データレプリケーション
// 同期 vs 非同期レプリケーション
const REPLICATION_STRATEGIES = {
synchronous: {
description: "プライマリとセカンダリの両方に書き込みが完了してからACK",
consistency: "強い一貫性",
latency: "高い(リージョン間RTT: 100-300ms)",
availability: "レプリカ障害時に書き込みがブロックされる",
useCase: "金融、決済など一貫性が最優先",
},
asynchronous: {
description: "プライマリに書き込み完了後にACK、セカンダリへは後から伝播",
consistency: "結果整合性(レプリケーションラグあり)",
latency: "低い(プライマリのみで完了)",
availability: "障害時のデータロスの可能性(RPO > 0)",
useCase: "ほとんどのWebサービス",
},
semiSynchronous: {
description: "少なくとも1つのレプリカに同期書き込み",
consistency: "中程度の一貫性保証",
latency: "中程度",
availability: "1レプリカ障害に耐えられる",
useCase: "バランスが必要な場合",
},
};
競合解決
// Active-Activeでの書き込み競合の解決
interface ConflictResolution {
strategy: string;
description: string;
tradeoff: string;
}
const CONFLICT_RESOLUTION_STRATEGIES: ConflictResolution[] = [
{
strategy: "Last Write Wins (LWW)",
description: "タイムスタンプが新しい方を採用",
tradeoff: "実装が簡単だがデータロスの可能性",
},
{
strategy: "CRDT (Conflict-free Replicated Data Type)",
description: "データ構造自体が競合を自動解決",
tradeoff: "データロスなしだが、使えるデータ構造が限定的",
},
{
strategy: "Application-level Resolution",
description: "アプリケーションロジックで競合を解決",
tradeoff: "柔軟だが実装が複雑",
},
{
strategy: "Region-based Sharding",
description: "データのオーナーリージョンを決め、そこでのみ書き込み",
tradeoff: "競合自体を回避できるが、リージョン間の書き込みが必要な場合に課題",
},
];
グローバルルーティング
// DNSベースのルーティング
const ROUTING_STRATEGIES = {
geolocation: {
method: "地理的位置ベースのDNSルーティング",
how: "ユーザーのIPアドレスから最寄りのリージョンに誘導",
tool: "Route 53 Geolocation Routing / Cloudflare Load Balancing",
},
latency: {
method: "レイテンシベースのルーティング",
how: "各リージョンへのレイテンシを計測し、最速のリージョンに誘導",
tool: "Route 53 Latency Routing",
},
failover: {
method: "ヘルスチェックベースのフェイルオーバー",
how: "プライマリリージョンの障害を検出し自動でセカンダリに切り替え",
tool: "Route 53 Failover Routing + Health Checks",
},
};
// 全体アーキテクチャ
// ユーザー → Global DNS → 最寄りリージョンの CDN/Edge
// → 最寄りリージョンの API サーバー
// → ローカル読み取りレプリカ
// → 書き込みはプライマリリージョンへ転送
RPOとRTO
// 障害復旧の指標
interface DisasterRecoveryMetrics {
// RPO (Recovery Point Objective): データロスの許容量
rpo: {
definition: "障害時にどこまでのデータを失ってよいか";
synchronousReplication: "RPO = 0(データロスなし)";
asynchronousReplication: "RPO = レプリケーションラグ(秒〜分)";
dailyBackup: "RPO = 最大24時間";
};
// RTO (Recovery Time Objective): 復旧までの許容時間
rto: {
definition: "障害からサービス復旧までの許容時間";
activeActive: "RTO ≈ 0(即座にフェイルオーバー)";
activePassive: "RTO = 数分〜数十分";
backupRestore: "RTO = 数時間";
};
}
// RPO/RTOの目標に応じた構成選択
const DR_CONFIGURATIONS = [
{ rpo: "0", rto: "< 1分", config: "Active-Active + 同期レプリケーション", cost: "最高" },
{ rpo: "< 1分", rto: "< 5分", config: "Active-Passive + 非同期レプリカ", cost: "高" },
{ rpo: "< 1時間", rto: "< 30分", config: "Active-Passive + 定期スナップショット", cost: "中" },
{ rpo: "< 24時間",rto: "< 4時間", config: "バックアップ + 別リージョン復元", cost: "低" },
];
まとめ
| ポイント | 内容 |
|---|---|
| 3つのパターン | Active-Passive, Active-Active, Read Local Write Global |
| レプリケーション | 同期(一貫性重視)vs 非同期(レイテンシ重視) |
| 競合解決 | LWW, CRDT, リージョンシャーディング |
| RPO/RTO | 目標に応じた構成とコストのトレードオフ |
チェックリスト
- 3つのマルチリージョンパターンを比較できた
- 同期/非同期レプリケーションのトレードオフを理解した
- 競合解決の戦略を3つ以上挙げられた
- RPO/RTOに基づくDR構成を選択できた
次のステップへ
次は演習です。ミッションクリティカルなシステムの設計に挑戦しましょう。
推定読了時間: 40分