一般社団法人 全国個人事業主支援協会

COLUMN コラム

  • データベースシャーディングの設計原則:水平分割の戦略と実装

データベースシャーディングとは何か

アプリケーションの成長に伴い、単一のデータベースサーバーでは処理しきれないデータ量やトラフィックに直面する場面が増えてきます。そこで登場するのがシャーディング(水平分割)という手法です。シャーディングとは、データを複数のデータベースインスタンスに分散配置することで、個々のサーバーにかかる負荷を軽減し、システム全体のスケーラビリティを確保する設計パターンです。

筆者はこれまで複数のプロジェクトでシャーディングの設計・運用に携わってきましたが、正直に言えば「導入しなくて済むなら導入しないほうがよい」技術のひとつです。それでも必要になるケースは確実に存在し、その際に正しい設計原則を知っておくことが、運用の成否を大きく分けます。

シャーディングが必要になるタイミング

シャーディングの導入を検討すべきタイミングは、以下のような状況が重なったときです。

  • 垂直スケーリング(スペックアップ)の限界に達している
  • リードレプリカだけでは読み取り負荷を分散しきれない
  • 単一テーブルのレコード数が数億件を超え、インデックスの効率が低下している
  • 書き込み負荷が特定のテーブルに集中している

逆に言えば、これらの条件を満たしていないのにシャーディングを導入するのは、複雑さに対してメリットが見合わない過剰設計になりがちです。まずはインデックスの最適化、クエリチューニング、キャッシュ戦略の見直しを先に行うべきです。

シャーディングキーの選定が最も重要

シャーディング設計において、最も重要な意思決定はシャーディングキーの選定です。シャーディングキーとは、データをどのシャードに配置するかを決定するためのカラムのことです。この選択を誤ると、後から修正するのは非常に困難になります。

良いシャーディングキーの条件は以下の通りです。

  • カーディナリティが高い:値のバリエーションが豊富で、データが均等に分散される
  • クエリの条件に頻繁に含まれる:ほとんどのクエリでシャーディングキーが指定されるため、クロスシャードクエリを最小限にできる
  • データの偏りが少ない:特定のシャードにデータが集中しない(ホットスポット問題の回避)
  • 時間経過で均等に増加する:特定の時期に偏りが発生しない

たとえばECサイトであれば、ユーザーIDをシャーディングキーにするのが一般的です。ユーザーに紐づくデータ(注文履歴、カート、お気に入りなど)が同じシャードに格納されるため、ユーザー単位の操作はシャードをまたがずに完結します。

主要なシャーディング戦略

レンジベースシャーディング

シャーディングキーの値の範囲によってデータを分割する方式です。たとえばユーザーIDが1〜100万はシャード1、100万1〜200万はシャード2、という具合です。理解しやすく実装もシンプルですが、データの偏りが発生しやすいという欠点があります。新規ユーザーが最新のシャードに集中するため、特定シャードへの書き込み負荷が高くなりがちです。

ハッシュベースシャーディング

シャーディングキーにハッシュ関数を適用し、その結果によってシャードを決定する方式です。データの分散が均等になりやすいのが大きな利点です。ただし、レンジクエリ(範囲検索)の効率が悪くなるというトレードオフがあります。

ディレクトリベースシャーディング

どのデータがどのシャードにあるかのマッピングを別のサービスやテーブルで管理する方式です。柔軟性が最も高いですが、ルックアップのオーバーヘッドが発生し、マッピングテーブル自体が単一障害点になるリスクがあります。

クロスシャードクエリの現実

シャーディングを導入すると、避けて通れないのがクロスシャードクエリの問題です。たとえば「全ユーザーの注文数ランキング」のようなクエリは、全シャードにクエリを発行して結果をマージする必要があります。

実務的な対処方法としては、以下のアプローチがあります。

  • 非正規化:集計データを別のストアに保持し、リアルタイム性を妥協する
  • CQRSパターン:書き込みと読み取りのモデルを分離し、読み取り専用の集約ビューを構築する
  • バッチ処理:定期的に全シャードからデータを収集して集計する
  • ストリーム処理:変更データキャプチャで各シャードの変更を捕捉し、リアルタイムに近い集計を行う

いずれの方法も結果整合性を許容する設計が前提となります。強い整合性が必要な処理は、できる限り単一シャード内で完結させることが鉄則です。

リシャーディングという最大の課題

ビジネスの成長に伴い、シャード数を増やす必要が出てくることがあります。これがリシャーディングです。ハッシュベースの場合、シャード数を変えるとハッシュの分配先が変わるため、大量のデータ移行が必要になります。

この問題を軽減するために、コンシステントハッシングの採用が有効です。シャード追加時に移行が必要なデータ量を最小限に抑えることができます。また、最初から十分な数の仮想シャード(バーチャルシャード)を用意しておき、物理サーバーへのマッピングを変更するアプローチも実践的です。

運用で学んだ教訓

シャーディング環境の運用では、以下の点を特に意識しています。

  • 監視の粒度を上げる:シャードごとのデータ量、クエリ数、レイテンシを個別に監視します。全体の平均値だけでは偏りを検知できない
  • スキーマ変更の慎重さ:全シャードに対してDDLを適用する必要があるため、ローリングアップデートの仕組みが必須
  • バックアップとリストアの複雑さ:ポイントインタイムリカバリを全シャードで整合性を保って実施するのは想像以上に難しい
  • テスト環境の構築:本番と同じシャード構成をテスト環境で再現することのコストを見積もっておく

シャーディングは銀の弾丸ではなく、運用コストと複雑性を大幅に増加させるトレードオフを伴う技術です。導入の判断は慎重に、しかし必要だと判断したら設計原則に忠実に進めることが、長期的な運用の安定につながります。

この記事をシェアする

  • Twitterでシェア
  • Facebookでシェア
  • LINEでシェア