【実務・中級編】 マルチリージョン構成 – Cloud Spanner

【Cloud Spanner】マルチリージョン構成の真実:世界を股にかける分散データベースを『正しく』調律する方法

こんにちは。テックリードの私だ。
今日のコードレビュー、あるいは設計レビューで、君たちはまた「とりあえずマルチリージョンにしておけば可用性は完璧ですよね」という甘口の設計書を持ってきたな?

……待ちなさい。その設計、本当にレイテンシの要件を満たしているか? コストの試算はスプリット秒単位で行ったか?
「マルチリージョンだから速くて落ちない」というのは、Cloud Spannerの表面しか見ていない素人の発想だ。光速の壁、Paxosアルゴリズムの物理的制約、そしてGoogleの広大なWAN(Wide Area Network)の裏側を理解していなければ、君たちが組んだグローバルシステムは、単に「高い金を払って遅くなったデータベース」に成り下がる。

今日は、Cloud Spannerのコアアーキテクチャであるマルチリージョン構成について、綺麗事抜きの実務的知見を叩き込む。準備はいいか?

—

1. なぜ「なんとなくマルチリージョン」では地獄を見るのか?

Cloud Spannerは、単一リージョン(Regional)であっても、3つのGoogle Cloudリージョン(厳密には可用性ゾーン)にまたがり、Paxosグループを組んで同期レプリケーションを行っている。これだけでも十分すぎる耐障害性(99.999%のSLA)を持つ。

では、なぜあえてマルチリージョン(Multi-region)を選ぶのか?
理由は主に2つだ。

1. 真のディザスタリカバリ(DR): リージョン全体が物理的に消滅するレベルの大規模障害からの生存。
2. 真のローカル読み書き(レイテンシの最適化): ユーザーの物理的近接性。

だが、ここで物理の壁が立ちはだかる。「光速の壁」だ。
例えば、東京(`asia-northeast1`)とアイオワ(`us-central1`)の間を光が往復するには、物理的にどうあがいても数十ミリ秒の時間がかかる。マルチリージョン構成における書き込みは、異なる大陸のリーダーレプリカ間で合意(PaxosのQuorum)を取る必要がある。

つまり、「マルチリージョン化=書き込みレイテンシの増大」はトレードオフではなく、物理法則なのだ。この事実を受け入れた上で、どう設計するか。それがプロの腕の見せ所だ。

—

2. Spannerマルチリージョン構成のトポロジーを暴く

Google Cloudが用意している標準のマルチリージョン構成(例: `nam-eur-asia1` のようなカスタム、あるいは `asia1` など)をそのまま使っていませんか?

マルチリージョンを設計する上で絶対に押さえておかなければならないのが、「リーダー(Leader)の配置」と「リード・レプリカ(Read-only Replica)の役割」だ。

リーダーとワーカーの力学

Spannerのデータは「スプリット」という単位に分割され、それぞれが独立したPaxosグループ(通常5つのレプリカを持つ)として管理される。マルチリージョン構成では、これらのレプリカが地理的に離れたリージョンに配置される。

  • リーダー・レプリカ: 読み取りと書き込みの調整(コミット)を行う。
  • リード・ライティング・レプリカ: リーダーの選挙権を持ち、書き込みの合意に参加する。
  • リード・オンリー・レプリカ: 書き込みの合意には参加しない(コストが安い)。レイテンシを抑えた読み取り(Stale Read)に特化する。

【設計の急所】真の「ローカル書き込み」は存在しない

マルチリージョン構成において、遠隔地のユーザーからの書き込みは、最終的にリーダーがいるリージョンへネットワークを飛ぶことになる。もし君のアプリケーションが東京にあり、Spannerのリーダーがオレゴンにあるような構成にしていたら……想像するだけで背筋が凍るだろう?

—

3. 堅牢な設計パターン:レイテンシと一貫性のハザードを回避せよ

実務でマルチリージョンを導入する際、以下の3つの設計パターンを状況に応じて使い分ける必要がある。

パターンA:グローバル・シングルライター + リード・オンリー最適化(王道パターン)

  • ユースケース: ECサイトのカタログ、マスタデータなど、「書き込みは少ないが、世界中どこからでも爆速で読み込みたい」システム。
  • 設計のキモ:
  • 書き込みは特定の主要リージョン(例: `asia1` なら東京)に集約し、他リージョン(台湾など)にはリード・オンリー・レプリカを置く。
  • 読み込みは `Stale Read(古いデータの許容)` を活用し、手元のリード・オンリー・レプリカからミリ秒単位で引く。

— 【コードレビューのポイント】
— グローバルなユーザー向けに、直近5秒以内の古いデータを許容してレイテンシを極限まで削るクエリ
SELECT item_id, name, price
FROM items
@{FORCE_STALeness=_COMMIT_TIMESTAMP-INTERVAL 5 SECOND}
WHERE category_id = 101;

> Tech Lead’s Comment:
> 「全トランザクションで強整合性(Strong Read)が必要ですか?」と自問しなさい。商品詳細ページの閲覧で0.5秒前のデータが見えたところで、ビジネス上の致命傷になるか?ならないはずだ。Stale Readの積極的活用こそが、マルチリージョンを制する。

パターンB:マルチプル・リーダー(デュアル・リージョン等の特殊構成)

  • ユースケース: 欧州と北米の両方で激しい書き込みが発生し、データ主権(GDPRなど)の観点から特定のリージョン間でデータを閉じ込めつつ、グローバル統合したい場合。
  • 設計のキモ: スキーマ設計の段階で、ユーザーIDやテナントIDを主キー(PrimaryKey)の先頭に持たせ、データ配置(Directory / Interleaving / `default_leader` ディレクティブ)を制御する。

—

4. パフォーマンス上の罠:見落とされがちな「3つのアンチパターン」

現場のレビューで私が必ず指摘する、マルチリージョン構成での「やらかしポイント」を挙げておく。

1. 不適切なプレースメント(Placement)によるクロスリージョンホップ

データをインターリーブ(親子関係)させる際、親と子の配置ポリシーがミスマッチを起こしていると、単一のトランザクション内で不必要なクロスリージョン通信が発生し、レイテンシが爆発する。
親テーブルのリージョン設定と、子テーブルの分散キーが一致しているかを必ず確認しろ。

2. トランザクション内での外部API呼び出し

「トランザクションの中でついでに外部の決済APIを叩こう」――論外だ。
マルチリージョン環境でこれをやると、ネットワーク遅延のブレがそのままトランザクションのロック保持時間に直結し、Spanner全体のスループット(TPS)を盛大に殺すことになる。外部連携は必ず非同期(Pub/Sub等)に逃がせ。

3. モニタリングの怠慢

Cloud Spannerのコンソールで「CPU使用率」だけ見て安心していないか?
マルチリージョンでは、「Cross-region latency」と「Paxos latency」のメトリクスを監視しなければならない。海底ケーブルの障害やプロバイダのルーティング変更によるレイテンシのスパイクは、静かにアプリケーションを蝕む。

—

5. チーフアーキテクトからの最終提言

Cloud Spannerのマルチリージョン構成は、魔法の杖ではない。物理的制約をエンジニアリングの力でいなすための「強力だが扱いが難しい重火器」だ。

設計の鉄則をもう一度胸に刻め:
1. 書き込みの物理的コストを理解し、書き込みパスを最小化せよ。
2. 読み込みは可能な限りStale Readを活用し、ローカルのレプリカを殴れ。
3. スキーマ設計(主キー設計)でデータの局所性をコントロールしろ。

この3つをクリアした時、君たちのシステムは、地球の裏側で何が起きようとも揺るぎない、真のグローバル・レジリエンスを手に入れる。

さて、理論はここまでだ。
今から出す君たちのプルリクエスト、本当にマルチリージョンの特性を活かしたコードになっているか……。
厳しいレビューを期待しておきたまえ。

コメント

タイトルとURLをコピーしました