【実務・中級編】 ノード (Node) – Cloud Spanner

Spannerの「ノード」を支配する者:真のスケールアウトを引き出すアーキテクチャの極意

こんにちは。テクニカルリードの私だ。
今日のコードレビュー、あるいは基本設計レビューで、こんなやり取りをしていないだろうか?

> 「とりあえずノード数を『3』にしておけば大丈夫っすよね。足りなくなったらオートスケーリングするし」

待て。その設計、本番の高負荷時に必ずスループットが頭打ちになるか、無駄なインフラコストを垂れ流すかのどちらかだ。

Cloud Spannerにおける「ノード (Node)」とは、単なるCPUとメモリの箱ではない。Spannerという世界最大級の分散データベースの心臓部であり、その物理的・論理的境界を理解しているかどうかが、プロのエンジニアと「お祈りデプロイ」を繰り返す素人の分かれ道だ。

今日は、Spannerのノードの深淵を覗き、実務で絶対に踏み抜いてはいけないアンチパターンと、限界を引き出す設計哲学を伝授しよう。

—

1. そもそも「ノード」とは何をしているのか?

Spannerのドキュメントを開けば、「ノードはコンピューティングリソースの単位であり、スループットとストレージ容量を提供する」と書いてある。だが、これだけでは表面的な理解に過ぎない。

内部構造の解像度をグッと上げよう。

[Cloud Spanner インスタンス]
┣━━ ノード 1 (Compute + Storage/Spits)
┃ ┣━━ スプリット A (Key Range: A ~ M)
┃ ┗━━ スプリット B (Key Range: N ~ Z)
┣━━ ノード 2 (…)
┗━━ ノード 3 (…)

1つのノードは、厳密にはGoogleの厳重なコンテナ基盤上で稼働するプロセス群であり、複数の「スプリット (Splits)」をホストするコンテナだ。
データはキーの範囲(Key Range)によって自動的にスプリットに分割され、これらのスプリットがノード間を動的に移動(バランシング)する。

ここで重要なのは、「1ノードあたりのリソース上限」と「データの偏り(ホットスポット)」の関係だ。

ノードあたりのハードリミットと現実

  • ストレージ容量: 1ノードあたり最大 2 TB 推奨(パフォーマンスを維持する場合)。
  • CPU使用率: 読取(Read)はともかく、書込(Write)のパクスレイ(Paxos)合意形成にはCPUを激しく消費する。

もし、あなたが「合計3TBのデータがあるから、2ノードで足りるな」と計算したとする。しかし、そのデータの8割が特定のテナントID(例:`tenant_id = ‘A’`)に集中していたらどうなるか?
3TBのうち2.4TBを管理するスプリットがたった1つのノードに張り付き、そのノードのCPUだけが100%に張り付く。これが「ホットスポット」の悪夢だ。ノード数をいくら増やしても、この偏りが解消されない限り、そのノードがボトルネックとなってシステム全体が沈没する。

—

2. 実務で直面する「ノード設計」のアンチパターン

設計レビューで私が真っ先にチェックするのは、テーブルのプライマリキー(PK)の設計と、それに伴うノードリソースの偏り予測だ。

❌ 愚劣な設計:連番ID、タイムスタンプ先頭のPK

— 【絶対にやるな】これでは全ての書込が単一のノードに集中する
CREATE TABLE Transactions (
TransactionId INT64, — または TIMESTAMP
UserId STRING(64),
Amount INT64,
) PRIMARY KEY (TransactionId);

なぜダメなのか?
`INT64`のインクリメントや`TIMESTAMP`をPKの先頭に置くと、新しいデータは常に「テーブルの最末尾(最大のキー範囲)」に書き込まれる。これはSpannerの動的なスプリット分割のアルゴリズムを嘲笑うかのように、一瞬の間にたった1つのスプリットに書込を集中させ、単一ノードを窒息させる。

⭕ 模範解答:ハッシュ化・分散キーによるインターリーブ・プレフィックス

ノードの真のスケールアウト能力を引き出すには、書込の負荷をすべてのノードに均等に分散させる(シャードする)必要がある。

— 【推奨】UUIDやハッシュプレフィックスを用いて、キー空間全体に書込を散らす
CREATE TABLE Transactions (
— 最初の数ビットにハッシュやランダム値を混ぜる、あるいはUUID v4を使用
ShardId INT64,
TransactionId STRING(64),
UserId STRING(64),
Amount INT64,
) PRIMARY KEY (ShardId, TransactionId);

このように、キーの先頭に高いカーディナリティを持つ分散要素(プレフィックス)を入れることで、データとスプリットは綺麗に全ノードへ分散し、ノード数を増やした分だけリニアにスループット(QPS)がスケールするようになる。

—

3. オートスケーリングの罠:実運用で知るべき挙動

「Spannerにはオートスケーリングがあるから安心」と思っていないか?
確かにGoogle Cloudは素晴らしいオートスケーリング機能を提供している。しかし、分散データベースの物理的制約を無視した魔法の杖ではない。

スケーリングのタイムラグと「予熱」

スプリットの移動や、新しいノードのプロビジョニングには数分単位のタイムラグが存在する。
ブラックフライデーや、毎時0分のバッチ処理開始など、「突発的かつ爆発的なトラフィック増」が予想されるシーンにおいて、オートスケーリングの追従を待っていたのでは、システムが耐えきれずにレイテンシの悪化(タイムアウトの嵐)を招く。

チーフアーキテクトからの提言:

  • 予測可能な高負荷の前には、必ず手動でノード数をスケールアップ(オーバプロビジョニング)しろ。
  • 負荷が去ったら元に戻す。この「プリ・スケーリング(事前スケール)」の運用プロセスをCI/CDやオペレーション手順に組み込むこと。これがプロのインフラ運用だ。

—

4. パフォーマンス監視の急所:どのメトリクスを見るべきか

Cloud Spannerのパフォーマンスチューニングにおいて、見るべきメトリクスは決まっている。Cloud Monitoringで以下のグラフをダッシュボードの最上段に配置しろ。

1. CPU Utilization (High Priority):

  • これが65%を超えたら黄色信号、80%を超えたら赤信号だ。特にパクスレイの合意形成を行う「High Priority CPU」の偏りは、特定のノードに負荷が集中している(=ホットスポットが発生している)決定的な証拠。

2. Storage utilization per node:

  • 1ノードあたり2TBを超えていないか。超えている場合、ストレージ起因のレイテンシ劣化や、スプリットの肥大化による再分割のオーバーヘッドが発生する。

負荷分散の確認用クエリ(INFORMATION_SCHEMA)

現在のスプリットがどのようにノードに配置され、どこに負荷が偏っているかを調査するためのクエリを授けよう。

— スプリットごとの統計情報を取得し、偏りがないか監査するクエリ
SELECT
t.table_name,
s.split_id,
s.row_count,
s.bytes
FROM
— INFORMATION_SCHEMAを活用したスプリット分析
— ※実際の環境やバージョンに応じシステムテーブルの仕様を確認すること
SPANNER_SYS.TABLE_STATISTICS_BY_INTERVAL_TOP_N(
TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 1 HOUR)
) stats
— チューニングの現場では、システムビューを結合してスプリットの偏りを可視化する

(※実務では、GCPコンソールの「Spanner Studio」やCloud Monitoringの熱地図(Heatmap)を併用して、どのキー範囲が炎上しているかを一目で特定できるようにしておくこと)

—

5. 結びにかえて:ノードを制する者はSpannerを制す

Cloud Spannerのノードは、ただの「サーバーの代わり」ではない。
背後にある数千、数万のストレージと計算資源を美しく調停し、グローバル規模のトランザクションを矛盾なく裁くための「抽象化されたエネルギーの塊」だ。

  • キー設計で分散を担保し、すべてのノードに公平に仕事をさせよ。
  • オートスケーリングに過信せず、ビジネスのピークには自らの手でリソースをねじ込め。
  • ホットスポットを恐れ、常にモニタリングの目を光らせろ。

この原則を遵守すれば、Spannerはその圧倒的な可用性とリニアスケーラビリティで、あなたのビジネスを絶対に裏切らない。

さあ、今日の設計レビューに戻ろう。君たちのチームのテーブル定義、本当に「分散」できているか?

コメント

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