【Cloud Spanner設計レビュー】マルチリージョン構成の物理的真実:レイテンシとクォーラムの限界を突破するトポロジー設計
設計レビュー会へようこそ。私はチーフアーキテクトだ。
今日の議題は、Cloud Spannerの真骨頂である「マルチリージョン構成におけるレプリカ配置の物理的トポロジー」についてだ。
「マルチリージョンにしておけば可用性は完璧だ」
「グローバル展開だから、とりあえず主要な大陸にレプリカを散らせばいい」
もし、君のチームでそんな安易な設計がまかり通っているなら、今すぐホワイトボードの前に戻ってこい。Cloud Spannerは魔法の箱ではない。光速の物理法則とPaxosアルゴリズムの数学的制約に支配された、極めて厳格な分散データベースだ。
今回は、マルチリージョン構成の裏側にある物理的実態を丸裸にし、レイテンシとクォーラム(定足数)の制約をねじ伏せて実用的なシステムを組み上げるための「極限の知見」を伝授する。
—
1. 物理的トポロジーの基礎:マルチリージョンは何を隠しているか?
Cloud Spannerのマルチリージョンインスタンスをデプロイするとき、GCPのコンソールで「リージョン」を選ぶだけで安心していないか?
Cloud Spannerのマルチリージョンは、最低でも3つのGCPリージョン(またはマルチリージョン内の複数のゾーン)にまたがり、リードライト(RW)レプリカとリードオンリー(RO)レプリカ、そしてウォッネス(Witness)レプリカが精密に配置される。
ここで、まず頭に叩き込むべき物理法則がある。「地球上において、光はガラス繊維の中を秒速約200,000kmでしか進まない」という事実だ。
クォーラム形成のコスト
Spannerの書き込み(Write)がコミットされるためには、Paxosグループの過半数(Quorum)の合意が必要だ。
例えば、3リージョンにまたがる構成(例: `nam-eur-asia` のようなカスタムではなく、標準的なマルチリージョン)において、あるパーティションのリーダーが東京にあるとする。アイオワ(米国)とフランクフルト(欧州)のレプリカと協調して書き込みを確定させるには、物理的な往復レイテンシ(RTT)の最大の壁を越えなければならない。
- 東京 ⇄ アイオワ: 約 110ms 〜 130ms RTT
- 東京 ⇄ フランクフルト: 約 170ms 〜 200ms RTT
書き込みレイテンシの下限値は、この「最も遠い必要ノードとのラウンドトリップ時間」に支配される。いくらコードを最適化しようとも、物理的制約より速く書き込みを完了させることは神サマに祈っても不可能だ。
—
2. レプリカの役割と配置の罠
マルチリージョン構成では、レプリカの種類を正しく理解し、地理的特性に合わせて配置をコントロールする必要がある。
| レプリカ種別 | 役割 | Paxos投票権 | 読取り参加 | 物理的配置の注意点 |
| :— | :— | :— | :— | :— |
| Read-Write (RW) | 読み書き、リーダー選出 | 有り | 可 | 可用性のために独立した3つのゾーン/リージョンに分散必須 |
| Read-Only (RO) | 読み取り専用(スナップショット) | 無し | 可 | ローカルレイテンシでの読み取り(Stale Read)を提供 |
| Witness | クォーラム形成のみ | 有り | 不可 | データを持たず投票権のみ。2-phase commitの過半数割れを防ぐ奇策 |
設計レビューにおけるアンチパターン:「全リージョンRW化の幻想」
「すべてのリージョンで書き込みを高速化したいから、全リージョンにRWレプリカを置こう」
――これは最悪の悪手だ。
地理的に離れたRWレプリカ間でPaxosの過半数を取ろうとすると、すべての書き込みがグローバルネットワークの最悪レイテンシ(Worst-case RTT)に引きずられる。結果として、P99レイテンシが数百ミリ秒に跳ね上がり、スループットは激減する。
【正しいアプローチ】
メインのトラフィックソース(例: アジア)にプライマリのRWレプリカ群を集中させ、他リージョン(例: 欧州・米州)にはROレプリカを配置する。真のグローバル書き込みが必要な場合は、アプリケーション層でシャードを切るか、後述するプレイスメント最適化を行うべきだ。
—
3. リージョン間レイテンシを飼いならす:設計パターン
では、この物理的制約の中で、どうやってミリ秒単位のレイテンシを要求されるシステムを構築するのか?実務で使える2つのパターンを提示する。
パターンA:マルチリージョン・リード最適化アーキテクチャ(王道)
グローバルに展開するECサイトやSaaSのユーザープロファイル管理などを想定してほしい。
- 書き込み: プライマリリージョン(例: `asia-northeast1`)に集約。現地のユーザーは書き込みに ~10ms、グローバルユーザーは ~150ms を甘受する。
- 読み取り: 各リージョンに配置したROレプリカに対し、Stale Read(古さ許容の読み取り)を実行する。
— 【コード例】数秒の遅延を許容し、ローカルのROレプリカから爆速で読み取るクエリ
— 強整合(Strong Read)を回避し、ネットワークホップを極小化する
SELECT
user_id,
user_name,
updated_at
FROM users@{FORCE_RO_STALE_READ=5}
WHERE country_code = ‘JP’;
> Architect’s Note:
> `FORCE_RO_STALE_READ` を適切に使うことで、グローバルユーザーであっても自リージョン内のROレプリカから数ミリ秒でデータを取得できる。データが数秒古くても問題ないユースケース(プロフィール、カタログ、設定情報など)では、このパターンが最強のパフォーマンスを発揮する。
パターンB:プレイスメント・キードメイン分割(高度)
特定の国や地域のデータ法規制(データレジデンシー)や、厳格な低レイテンシ要件(金融取引など)がある場合、Cloud Spannerのリージョン別プレイスメント(Fine-grained backup/instance placement)や、テーブルのパーティショニングを活用する。
特定のテナントや国のデータのみを、特定のリージョン群のPaxosグループに閉じ込めることで、不要なグローバル通信をバイパスする。
— 【設計例】テナントごとにデータを特定の物理リージョンへピン留めするスキーマ概念
CREATE TABLE TenantData (
TenantId INT64,
DataKey STRING(1024),
Payload BYTES(MAX),
) PRIMARY KEY (TenantId, DataKey)
— ディレクティブにより特定のリージョン配置グループに紐付ける(イメージ)
—
4. パフォーマンス上の注意点とトラブルシューティング
最後に、現場でよくやらかす致命的なミスを挙げておく。設計レビューのチェックリストとして活用してほしい。
1. 「グローバル・ホットスポット」の踏み抜き
マルチリージョン環境において、全リージョンから単一の行(例: グローバルなカウンターや単一のシーケンスID)に対して激しい書き込みを行うと、リーダーがいるリージョンへトラフィックが集中し、ネットワークの帯域枯渇とCPUスパイクを引き起こす。
- 対策: 連番やハッシュ化されていないキー(UUID v4やシャードキー)を使用し、書き込み負荷をスプリットさせること。
2. リージョン障害時のフェイルオーバー挙動の誤解
「マルチリージョンだから、1つのリージョンが消えてもノーダウンタイムだよね?」
――半分正しく、半分間違っている。
Spannerは自動的に生き残ったレプリカで新しいリーダーを選出し、数秒以内に書き込みを再開する(High Availabilityの担保)。しかし、生き残ったノード数がクォーラム(過半数)を維持できている場合に限る。
3リージョン構成で2リージョンが同時にダウンした場合、クォーラムは崩壊し、書き込みは停止する(可用性の犠牲と引き換えに整合性を守るのがSpannerの哲学だ)。
—
結論:今日の設計レビューの判定
今回のテーマである「マルチリージョン構成におけるレプリカ配置の物理的トポロジー」の結論はこうだ。
> 「物理法則をバイパスすることはできない。だからこそ、データの性質(書き込みの頻度、読み取りの鮮度要求、法的要件)を見極め、RWとROの配置をミリ単位・ミリ秒単位でデザインし尽くせ」
甘い設計は、本番環境のグローバルネットワーク上で必ず牙を剥く。
コードを書く前に、地球儀と光速を思い出せ。
さて、君たちの設計書の修正版を、明日の朝イチで持ってきてもらおうか。レビューを終了する。
コメント