Cloud Spannerの心臓部:スプリット管理という「物理」を設計の武器にする
多くのエンジニアがCloud Spannerを「無限にスケーリングする魔法のデータベース」と誤解している。だが、もし君がシステムのパフォーマンスを極限まで引き出したいと願うなら、その「魔法」の裏側にあるスプリット(Split)管理という物理的な現実を直視しなければならない。
今日は、Spannerがどのようにデータを物理的に裁断し、それをどうノード間で配置しているのか。そして、我々エンジニアがその挙動をどう「ハック」すべきか、核心を突こう。
—
1. スプリットとは何か:データという「帯」の裁断
Spannerにおいて、テーブルは単なる行の集合ではない。それはキーでソートされた巨大な「帯(Keyspace)」だ。
Spannerは、この帯を一定のサイズ(デフォルトでは数GB程度)ごとに切り分ける。これがスプリットだ。各スプリットは、Paxosグループという単位で管理され、物理的なノード(Spannerサーバー)に配置される。
重要なのは、「君たちが定義したテーブル構造が、そのまま物理的に分断される」という事実だ。
ここが設計の分かれ道
- シーケンシャルなキー(UUID v4ではないもの):
例えば `timestamp` や `sequential_id` を主キーの先頭にすると、すべての書き込みが「末尾のスプリット」に集中する。いわゆる 「ホットスポット」 だ。
- ランダムなキー(UUID v4やハッシュ化されたID):
書き込みが全スプリットに均等に分散される。これがSpannerの性能をフルに引き出すための「基本の型」だ。
—
2. スプリットの「移動」と「分割」:動的な適応
Spannerの真骨頂は、負荷に応じてスプリットをリアルタイムで再配置する機能にある。
1. Split: あるスプリットへのアクセス負荷が急増すると、Spannerは自動的にそれを2つに分割し、別のノードへ移動させる。
2. Move: ノード間の負荷バランスが崩れると、Spannerはバックグラウンドでスプリットを別のサーバーへマイグレーションする。
ここで注意すべきは「マイグレーションのコスト」だ。
急激なトラフィック増大は、Spannerがスプリットを分割・移動させるためのオーバーヘッドを生む。設計時にキーの設計を怠ると、この「再配置」が追いつかず、DBのレイテンシがスパイクするという悲劇を招く。
—
3. 実践的設計パターン:パフォーマンスを制御する
「とりあえずUUIDを使えばいい」という議論は、中級者までのものだ。プロはさらに一歩先を行く。
逆引き:インターリーブ(Interleave)の魔法
関連する親テーブルと子テーブルを物理的に同じスプリットに配置したい場合、インターリーブを使う。これは物理的近接性を高め、JOINのオーバーヘッドを劇的に減らす。
— ユーザーと注文履歴を物理的に近接させる設計
CREATE TABLE Users (
UserId INT64 NOT NULL,
…
) PRIMARY KEY (UserId);
CREATE TABLE Orders (
UserId INT64 NOT NULL,
OrderId INT64 NOT NULL,
…
) PRIMARY KEY (UserId, OrderId),
INTERLEAVE IN PARENT Users ON DELETE CASCADE;
— UsersのUserIdの隣に、そのユーザーのOrdersが物理的に配置される
避けられないホットスポットへの対抗策:キーのビット反転(Bit-reverse)
どうしてもシーケンシャルなIDを使わなければならない場合は、キーの先頭に「プレフィックス」を付与して分散させるテクニックがある。
— シーケンシャルなIDの先頭に、0-NのシャードIDを付与する
— これにより、末尾以外のスプリットにも書き込みを分散できる
INSERT INTO Orders (ShardId, OrderId, Data)
VALUES (MOD(user_id, 16), user_id, ‘…’);
—
4. チーフアーキテクトからの戒め
最後に、設計レビューで私がよく指摘する「落とし穴」を3つ挙げておく。
1. 大きな行(Large Rows)は罪である:
1つの行が数MBを超えるような設計は避けるべきだ。スプリット管理は行単位で行われるわけではないが、巨大な行はスプリットの分割を困難にし、特定のノードに不均衡な負荷を与える。
2. インデックスの設計を忘れるな:
テーブルだけでなく、セカンダリインデックスも独自の「スプリットの帯」を持つ。インデックスのキー設計が悪いと、メインテーブルは健康でもインデックス側でホットスポットが発生し、書き込み性能が死ぬ。
3. モニタリングを怠るな:
GCPコンソールの「Cloud Spanner スプリットの統計情報」を毎週見ているか?「どのキー範囲がどのノードで処理されているか」を可視化できて初めて、君はSpannerを「制御」していると言える。
—
結論
Cloud Spannerは「ブラックボックス」ではない。キーの設計というコードが、物理的なスプリットの配置を決定する「構成ファイル」として機能しているのだ。
君が書いたその一行が、世界中のデータセンターでどう物理的に配置されるのか。それを想像できるようになった時、君は初めてSpannerを使いこなしたと言えるだろう。
さあ、エディタに戻って、もう一度主キーの定義を見直してほしい。その設計は、本当に「分散」されているか?
コメント