なぜPostgreSQLを「分散」させるのか?— Citusによるスケーリングの現実解
「PostgreSQLでデータ量が億単位を超えてきて、VACUUMが追いつかない」「JOINの計算コストが高すぎて、クエリがタイムアウトする」。
そんな壁にぶち当たったとき、多くのエンジニアが「いよいよMySQLやNoSQLへの移行か?」と頭を抱えます。でも、ちょっと待ってほしい。そのPostgreSQL、Citusを使えば、今の資産を活かしたまま「分散データベース」へと進化させることができるんです。
今日は、僕が現場でCitusを導入する際に必ず叩き込まれる「シャードキー設計」の極意について話そうと思います。
—
Citusは魔法じゃない。設計の「痛み」はここにある
CitusはPostgreSQLを複数のノードに横展開する拡張機能です。でも、ただインストールして終わりではありません。最も重要なのは、「どのデータをどのノードに置くか」という設計思想です。
ここで登場するのが「シャードキー(分散キー)」。
これを適当に選ぶと、分散させたはずなのに特定のノードだけに負荷が集中する「ホットスポット」が発生したり、複数のノードをまたぐクエリが多発してパフォーマンスが地の底に落ちたりします。
シャードキー選びの鉄則:クエリの「主役」を狙え
シャードキーを選ぶときの黄金律は、これです。
> 「アプリケーションの主要なクエリにおいて、最も頻繁にフィルタリングやJOINが行われるカラムを選ぶこと」
例えば、SaaSのマルチテナント・データベースを考えてみましょう。ほとんどのクエリが `tenant_id` を条件にしているなら、迷わず `tenant_id` をシャードキーにします。
— テーブルを tenant_id で分散させる
SELECT create_distributed_table(‘orders’, ‘tenant_id’);
こうすることで、`tenant_id` を指定したクエリは、特定の1つのノードにルーティングされます。これを「ローカル実行」と言って、Citusにおけるパフォーマンスの要です。逆に、このキーを無視したクエリを投げると、Citusは全てのノードに問い合わせを行い、結果をマージする「分散クエリ」という重い処理を走らせることになります。
—
「共配置(Co-location)」という切り札
もう一つ、中級者以上なら必ず知っておくべきテクニックが「共配置」です。
例えば、`orders` テーブル(注文)と `line_items` テーブル(明細)をJOINしたいとします。もし両方のテーブルを同じ `tenant_id` で分散させておけば、Citusは「このデータは同じノードにあるはずだ!」と判断して、ネットワーク越しにデータを転送することなく、ノード内でJOINを完結させてくれます。
— orders テーブルを基準に line_items を分散させる(=同じノードに配置される)
SELECT create_distributed_table(‘line_items’, ‘tenant_id’, colocate_with => ‘orders’);
この「同じキーで関連テーブルを寄せる」という設計ができていないと、JOINのたびにネットワークが悲鳴を上げることになります。設計段階でER図を眺めながら、「どのカラムを軸にデータが塊を作っているか」を想像するのが、この仕事の醍醐味ですね。
—
避けるべき「アンチパターン」
逆に、やってはいけないシャードキー選定もあります。
- カーディナリティ(値の種類の多さ)が低すぎる: 例えば「性別」や「ステータス」で分散させると、データが数箇所にしか偏らず、スケールの恩恵を受けられません。
- 更新頻度が極端に高いキー: 特定のキーにデータが集中し続けると、そのノードのI/Oがボトルネックになります。
- キーが全く存在しないクエリが多い: 「全ユーザーの統計を出したい」というクエリがメインなら、Citusを導入する前に、そもそも読み取り専用のリードレプリカで事足りないか再検討しましょう。
—
最後に:完璧を求めすぎないこと
ここまで設計の話をしてきましたが、実務では「どうしてもシャードキーを跨いだJOINが必要」という場面も必ず出てきます。そんなときは、無理にパズルを完成させようとせず、Citusが提供する「リファレンステーブル(小さな共通テーブルを全ノードにコピーする仕組み)」などを活用して、柔軟に逃げ道を作ってください。
Citusは、PostgreSQLの使い勝手をそのままに、スケールアウトの力を与えてくれる素晴らしいツールです。でも、結局のところデータベース設計は「トレードオフとの戦い」です。
まずは小さなテーブルから分散させてみて、`explain` でクエリがどう走っているかを確認する。その繰り返しが、あなたを本当の意味での「データベースの達人」にしてくれるはずです。
もし運用していて「特定のノードが重いな」と感じたら、いつでもまた相談してください。インデックスの切り方から、シャードの再配置まで、また一緒に考えましょう。それでは、良いエンジニアリングを!
コメント