Cloud Spannerデータ配置ポリシーの極意:物理的制約をハックし、レイテンシとコンプライアンスを支配する
こんにちは。テックリードの私だ。
今日のコードレビュー、あるいはアーキテクチャ設計レビューで、こんなセリフを耳にして頭を抱えなかったか?
- 「とりあえずマルチリージョン(nam-eur-asia1)にしておけば可用性は完璧でしょ」
- 「データ置き場?GCPが勝手にいい感じにやってくれるはずだ」
もし君のプロジェクトでこの認識がまかり通っているなら、今すぐホワイトボードの前に座れ。Cloud Spannerは魔法の箱ではない。それは物理法則(光速の限界と地理的距離)の上で極限まで最適化された、超高度な分散RDBMSだ。
今回は、Spannerのコア・アーキテクチャの根幹をなす「データ配置ポリシー(Data Placement Policies)」について、実務で絶対に踏んではいけない地雷と、極限のパフォーマンスを引き出すための設計パターンを授けよう。
—
1. Spannerの「スプリット」と物理配置のリアル
まず、Spannerのストレージ層がどうなっているかをおさらいする。
Spannerのデータは、テーブルの主キーに基づいて「スプリット(Split)」と呼ばれる単位に分割され、各スプリットはPaxosグループによって冗長化される。
ここで重要なのは、「そのPaxosグループのレプリカが、どのリージョンやゾーンに配置されるか」を完全に制御するのが、データ配置ポリシーであるという点だ。
[クライアント] —> (低レイテンシ) —> [リーダーレプリカ (同リージョン)]
|
(Paxosコンセンサス)
|
+——————-+——————-+
| (別ゾーン/リージョン) | (別リージョン)
[リーダー候補レプリカ] [読み取り専用レプリカ]
デフォルトのマルチリージョン構成(例: `nam-eur-asia1`)は、広範囲な障害耐性を持つ一方で、書き込みや強い整合性を持つ読み取り(Read-Write Transaction)のたびに、大陸間を結ぶ海底ケーブルを往復する物理的なレイテンシペナルティを支払うことになる。
「なんとなくマルチリージョン」の代償は、数千ミリ秒のレイテンシと、無駄に膨れ上がるクラウドの請求書だ。この現実を直視しよう。
—
2. データ配置ポリシーの選択肢と「真のユースケース」
Cloud Spannerが提供する配置ポリシーは、大きく分けて以下の2つに大別される。
1. リージョン構成 (Regional Configurations)
- 単一リージョン内の複数ゾーンにレプリカを配置。
- 特徴: 書き込み・読み取りともに爆速(数ミリ秒)。同一リージョン内アプリとの組み合わせで真価を発揮。
- 弱点: リージョン全体の障害(極めて稀だがゼロではない)に対しては脆弱。
2. マルチリージョン構成 (Multi-regional Configurations)
- 複数の地理的リージョンにまたがってレプリカを配置。
- 特徴: 圧倒的な可用性、リージョン障害への耐性。
- 弱点: 物理的距離による書き込みレイテンシの増大。
ここでテクニカルリードとして問いたい。
「君たちの扱っているデータは、本当にすべてのトランザクションで地球規模の耐障害性が必要か?」
金融取引の台帳であれ、ECの決済であれ、法規制(コンプライアンス・データレジデンシー)やビジネス要件を冷静に分解すれば、すべてのデータをマルチリージョンに置く必要などないケースが大半だ。
—
3. 実践:カスタムデータ配置(Fine-Grained Custom Placement)の設計パターン
Spannerの真骨頂は、データベース全体だけでなく、テーブル単位、さらには行(Row)単位でデータの配置を制御できる「ファイングレイン・カスタム配置(Fine-Grained Custom Placement)」にある。
これを使えば、「ヨーロッパのユーザーデータはEUリージョンに閉じ込め、アジアのデータは東京に置く」というデータレジデンシー要件と、「グローバルで統一されたスキーマ」を両立できる。
設計例:テナントごと・地域ごとの配置制御
以下のDDLを見てほしい。特定のテーブルやパーティションに対して、どのリーダーリージョンを使うかを指定する実務的なアプローチだ。
— リージョンごとのマスターデータを配置するための親テーブル
CREATE TABLE Tenants (
TenantId INT64 NOT NULL,
RegionPolicy STRING(MAX) NOT NULL,
Name STRING(MAX),
) PRIMARY KEY (TenantId);
— 顧客データを格納するテーブル(テナントの配置ポリシーにインターリーブさせる)
CREATE TABLE CustomerData (
TenantId INT64 NOT NULL,
CustomerId INT64 NOT NULL,
DataPayload STRING(MAX),
) PRIMARY KEY (TenantId, CustomerId),
INTERLEAVE IN PARENT Tenants ON DELETE CASCADE;
ここに、Spannerのディレクティブ(※概念的な設定例)を組み合わせることで、データの物理的な存在場所を強制する。
実務では、データベース作成時や、プレースメント・バウンス(Placement Bounds)を活用したクエリ単位のルーティング、さらにはチェンジストリーム(Change Streams)と組み合わせた非同期レプリケーションを駆使して、「書き込みはローカル、参照はグローバル」なアーキテクチャを構築する。
—
4. パフォーマンス上の致命的な罠(落とし穴)
データ配置ポリシーを設計・運用する上で、私がレビュー時に必ずチェックする「3大アンチパターン」を挙げておく。これらを犯すと、スケーラビリティは一瞬で崩壊する。
罠①: ホットスポットを生むプレースメントの偏り
特定のリージョン(例えば `asia-northeast1`)だけに書き込みが集中するようなスキーマ設計にしておきながら、テーブルの主キーが連番(カウンタ)になっている場合。
スプリットが適切に分割されず、単一のノード(リーダー)に負荷が集中してCPU使用率が100%に張り付く。
- 対策: 主キーには必ずハッシュ化されたプレフィックスや、UUIDv4、あるいはリバースビット等の分散キーを採用し、スプリットを物理的にも均等に散らせ。
罠②: 読み取り専用レプリカの「古いデータ(Stale Read)」の誤用
マルチリージョン構成において、レイテンシを下げたいがために、安易に `Stale Read`(古いデータの読み取り)を多用する設計。
コンプライアンス上、あるいはビジネスロジック上で「直前の書き込みが反映されていないと致命的なデータ(例:残高引き落とし後の残高確認)」に対してStale Readを適用し、整合性バグを生む事故が後を絶たない。
- 対策: 「レイテンシが正義」の画面表示やログ分析にはStale Readを、厳密な整合性が必要なトランザクションにはRead-WriteまたはBounded Stalenessを厳格に使い分けろ。
罠③: クロスリージョントラフィックのコスト爆発
アプリケーションサーバーが東京(`asia-northeast1`)にあるのに、Spannerのデータベース設定をUS中心のマルチリージョンにしているケース。
トランザクションのたびに太平洋をデータが往復し、レイテンシが悪化するだけでなく、GCPのネットワークエグレス料金(転送料金)が毎月恐ろしい額に膨れ上がる。
- 対策: 「アプリとSpannerのリーダーレプリカは、物理的に同じリージョンに同居させる」。これがインフラコストとパフォーマンスを最適化する鉄則だ。
—
5. チーフアーキテクトからの提言
Cloud Spannerのデータ配置ポリシーを制する者は、グローバルスケールシステムのコストとパフォーマンスを制する。
「なんとなく便利そうだから」という理由でデフォルト設定に逃げるな。
- ユーザーはどこにいるのか?
- データの法的規制(GDPRや個人情報保護法)はどうクリアすべきか?
- 許容される最大のレイテンシは何ミリ秒か?
これらを徹底的に突き詰め、コードとDDLに反映させること。それが、真の意味で「Spannerを使いこなしている」と言えるエンジニアの姿だ。
次の設計レビューでは、君たちの口から「このテーブルのデータ配置は、〇〇の理由でこのリージョンにピン留めします」という言葉が出ることを期待している。
健闘を祈る。
コメント