【実務・中級編】 リーダー配置 – Cloud Spanner

【Cloud Spanner 伝説の知見】リーダー配置の罠と真実:書き込みレイテンシを極限まで支配する設計論

こんにちは。Cloud Spannerの内部挙動をレイヤー単位で剥ぎ取り、数々の修羅場をくぐり抜けてきたチーフアーキテクトだ。

今日のコードレビュー、あるいは基本設計レビューで、こんな設計書を見かけなかったか?

> 「マルチリージョン構成で可用性を高めつつ、書き込みレイテンシを抑えるために、リーダーレプリカを特定リージョンに固定する」

一見、もっともらしい。しかし、Spannerの「分散トランザクション」と「Paxosグループ」の物理律を理解していない人間がこの設計を実装すると、本番稼働直後に「なぜか書き込みが遅い」「特定のリージョンが落ちた瞬間にレイテンシが跳ね上がる」という悪夢を見る。

今日は、Cloud Spannerにおける「リーダー配置(Leader Placement)」の本質と、実務の現場で絶対に踏み抜いてはならないアンチパターン、そして極限のパフォーマンスを引き出すための設計パターンを授けよう。

—

1. Cloud Spannerのリーダー配置とは何か(物理的現実)

まず、教科書的な説明はスキップして、Spannerのエンジン内部で何が起きているのかを物理レイヤーで定義する。

Cloud Spannerは、データをシャーディングし、それぞれのシャード(スプリット)を複数のノードにPaxosグループとして冗長化している。

  • リーダーレプリカ(Leader Replica): 書き込み(Write)および強整合性読み取り(Read-Write Transaction)のコーディネーションを担当する。
  • フォロワーレプリカ(Follower Replica): リーダーからのPaxosログを受け取り、データを同期して読み取り専用トラフィック(Stale Read)をさばく。

重要なのは、「書き込みは常にリーダーで発生し、リーダーの合意形成(Quorum)を経なければコミットされない」という事実だ。

つまり、クライアントアプリケーションがどこから書き込みを投げようとも、データが属するスプリットのリーダーが物理的に遠く離れたリージョンにいれば、光速の壁(ネットワーク遅延)に阻まれる。リーダー配置を制することは、Spannerのレイテンシを制することと同義なのだ。

—

2. リーダー配置のモードとデフォルトの挙動

Spannerでは、データベース全体、あるいはテーブル/親ポインタ単位でリーダーの配置ポリシーを制御できる。

デフォルトでは、Spannerはワークロードのアクセスパターンを自動検知し、リーダーを動的に移動させる(Dynamic Leadership / Default Leadership)。大半のワークロードにおいては、この自動最適化に任せるのが最も安全だ。

しかし、次のような要件がある場合には、明示的なリーダー配置(Leader Placement)の介入が必要になる。
1. 特定の国・法規制(データ主権)への準拠:書き込みデータが特定のリージョン外に出てはならない。
2. マルチリージョン構成におけるレイテンシの完全制御:プライマリ・セカンダリの役割を明確にし、予測可能なレイテンシ担保したい。

—

3. 実務で直面する設計パターン:マルチリージョンでの最適解

東京(`asia-northeast1`)と大阪(`asia-northeast2`)のようなマルチリージョン構成、あるいはUSマルチリージョン(`nam-standard`等)を設計するときの典型的なアプローチを見ていこう。

アンチパターン:全リージョンからの「なんとなく書き込み」

東京と大阪にアプリサーバーを置き、データベースをマルチリージョン(例: `asia1`)で構築したとする。この時、リーダーの配置を意識せずデフォルトのままでいると、大阪のアプリから来た書き込みリクエストが、たまたま東京にいるリーダーにヒットし、無駄なラウンドトリップが発生する。さらに、リーダーが動的に大阪に移動すると、今度は東京からの書き込みが遅くなるという「リーダーフラッピング(動揺)」現象が起きる。

堅牢な設計パターン:ピニング(固定)とコロケーション(近接)

本番環境でレイテンシを極限まで詰める場合、「アプリケーションの主要なデプロイリージョン」と「リーダーレプリカ」を一致させる。

例として、次のようにテーブルのプロパティやデータベース設定でリーダーを特定のリージョンに寄せる(※概念的なDDL表現)。

— 特定のテーブルグループに対して、リーダーを asia-northeast1 (東京) に固定する例
— ※実際のSpanner DDLの構文やプレースメントポリシーの指定方法は最新のGCPドキュメントを参照のこと
ALTER TABLE Orders
SET OPTIONS (
leader_placement = ‘asia-northeast1’
);

この設計の肝は、「メインのトランザクションを発行するクライアントの物理的な位置」と「リーダー」の距離をゼロ(あるいは最小)にすることだ。東京のGKEクラスターからSpannerを叩くなら、リーダーも東京に置く。これが鉄則だ。

—

4. チーフアーキテクトが伝授する「パフォーマンス上の注意点」

実務のコードレビューで、私が必ずチェックするポイントを3つ挙げる。これを破る者は、私のプロジェクトでは容赦なく差し戻しだ。

① ゾーン・リージョン障害時の「フェイルオーバー遅延」を計算に入れているか?

リーダーを特定のリージョンに固定(Pin)した場合、そのリージョンで障害が発生すると、Spannerの基盤側で自動的に別のリージョンにリーダーが選挙(Election)によって移譲される。
この「フェイルオーバー」の間、数秒〜数十秒の書き込みレイテンシのスパイク、あるいは一時的なアボート(ABORTED)エラーが発生する。
「リーダー固定=可用性の低下」ではないが、「障害時のリトライハンドリング(冪等性と指数バックオフ)」の設計がよりシビアになることを忘れるな。

② ホットスポット(Hotspotting)との闘い

リーダーを特定リージョンに固定した上で、さらに「シーケンシャルなID(インクリメントする数値やタイムスタンプ先頭のキー)」をプライマリキーに選んだとしよう。
結果はどうなるか?
特定のリーダーノードのCPUが100%に張り付き、他のレプリカは暇を持て余すという、美しくない「ホットスポット」が完成する。
リーダー配置を最適化するなら、プライマリキーには必ずUUIDv4やハッシュ化されたプレフィックスを使い、トラフィックを空間的・時間的に完全にランダム分散させることが大前提だ。

③ 読込専用レプリカ(Read-Only Replica)との混同

「リーダーを大阪に置けば、東京からの読み込みも早くなるはずだ」――これは誤りだ。
読み込み性能をスケールさせたいだけなら、リーダーの配置をいじるのではなく、Stale Read(古いタイムスタンプでの読み込み)を活用し、ローカルのフォロワーレプリカを参照させるべきだ。リーダー配置はあくまで「書き込み(Read-Write)」のレイテンシ最適化のためのカードである。

—

5. まとめ

Cloud Spannerにおけるリーダー配置のコントロールは、単なる「設定値の変更」ではない。それは、物理的な地球のサイズと光速の限界に抗い、アプリケーションのトランザクション性能をデザインする高度なエンジニアリングだ。

設計レビューでこのテーマが出たら、こう問いかけろ。

> 「そのリーダー配置、クライアントの地理的分布と、ホットスポット対策、そしてフェイルオーバー時のリトライ戦略までロジカルに説明できますか?」

この問いに淀みなく答えられた時、そのシステムは真に堅牢で、スケーラブルなSpanner基盤となるだろう。

健闘を祈る。

コメント

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