データベースのシャーディングの仕組み — 理解が難しい理由
シャーディングはデータを複数ノードに分割してデータベースをスケールさせる手法だが、ルーティング、リバランス、シャード間の失敗モードを生み、システムを理解しにくくする。

シャーディングとは(そして何ではないか)
シャーディング(別名 水平分割)とは、アプリケーションから見ると「1つの」データベースに見えるもののデータを、複数のマシン(シャードと呼ぶ)に分割することです。各シャードは行の一部だけを保持しますが、全体としては完全なデータセットを表します。
1つの論理テーブル、複数の物理配置
役立つ考え方は、論理構造と物理配置の違いです。
- 論理的には:依然として「Users」テーブルが1つ(カラムや意味は同じ)あります。
- 物理的には:そのテーブルの行は別々の場所に保存されています—例えばID 1–1,000,000 がシャードA、次の100万がシャードBにある、という具合です。
アプリからは1つのテーブルのようにクエリを実行したいですが、内部ではシステムがどのシャードに話すべきかを決める必要があります。
レプリケーションでも垂直スケールでもない
シャーディングはレプリケーションとは異なります。レプリケーションは同じデータのコピーを複数のノードに作り、主に高可用性や読み取りスケールのために使います。シャーディングはデータを分割し、各ノードが異なるレコードを保持します。
また、垂直スケーリング(単一データベースをより大きなマシンに移す)とも異なります。垂直スケールは単純な場合が多いですが、実際には限界がありコストが急増します。
シャーディングが自動的に解決しないこと
シャーディングは容量を増やしますが、すべてのクエリが速くなるわけではありません。以下の点は残ります:
- 関連する行が異なるシャードにあれば ジョイン は高コストになる
- シャード間の トランザクション は困難で、全体原子性を保つには協調が必要になる
- 運用の複雑化:ルーティング、リバランス、デバッグ、障害対応がシステムの一部になる
したがってシャーディングは ストレージとスループットをスケールする手段 として理解するのが正しく、すべての挙動を自動的に良くする魔法ではありません。
チームがシャードする理由:解決しようとする問題
シャーディングはほとんどの場合最初の選択肢ではありません。多くのチームはシステムが成功して物理的限界に達したり、運用上の痛みが頻発するようになったときに選びます。動機は「シャーディングしたい」ではなく「1つのデータベースが単一障害点やコストの原因になって成長を阻害している」からです。
シャーディングに駆り立てる痛点
単一ノードが容量不足になるパターンはいくつかあります:
- ストレージ制限: テーブルやインデックスが増えディスクが逼迫し、バックアップが遅くなり保守が危険になる
- 書き込みスループットの限界: CPU、WAL/redo、ロック競合が書き込み/秒数を制限する
- 読み取りスループットの限界: キャッシュやレプリカを使っても一部ワークロードがプライマリを圧倒する
- ノイジーネイバー: あるテナントやワークロードがリソースを独占して他を劣化させる
これらが頻発する場合、多くは単一の悪いクエリが原因というより「一台の機械が過度な責任を負っている」ことが原因です。
目的:スケールアウト、分離、コスト管理
データベースのシャーディングはデータとトラフィックを複数ノードに分散させ、能力をマシン追加で拡張できるようにします。うまくやれば ワークロードの分離(あるテナントの負荷が他のレイテンシを壊さない)や、超大型インスタンスを避けてコストを管理することも可能です。
壁に近づいている初期警告サイン
繰り返し現れるパターン:ピーク時のp95/p99が定常的に上昇する、レプリケーションラグが長くなる、バックアップ/リストアが許容ウィンドウを超える、ちょっとしたスキーマ変更が大仕事になる等。
なぜ通常は最後の手段か
決断前にチームは通常、インデックスやクエリ改善、キャッシュ、リードレプリカ、単一DB内のパーティショニング、古いデータのアーカイブ、ハードウェアアップグレードといったより簡単な対策を使い尽くします。シャーディングはスケール問題を解けますが、協調や運用の複雑性、新しい障害モードを追加するためハードルは高くなるべきです。
コア要素:シャード、ルーター、メタデータ
シャード化されたデータベースは単独のものではなく、協調する小さなシステム群です。シャーディングが「理解しにくい」と感じられる理由は、正しさと性能が単一のDBエンジンではなくこれらの部品の相互作用に依存するためです。
シャード:独立したパーティション(各自インデックスを持つ)
シャードはデータのサブセットで、通常はそのサーバやクラスター上に保存されます。各シャードは通常:
- ストレージ(データファイル)
- インデックス(そのシャード内で高速にクエリできるように)
- ローカル制限(CPU、メモリ、ディスク、接続数)
アプリから見るとシャード化構成は1つの論理データベースに見せようとしますが、単一ノードの「インデックス検索1回」が「正しいシャードを見つけてからの検索1回」に置き換わる点に注意が必要です。
ルーター/コーディネータ:リクエストを正しいシャードへ届ける仕組み
ルーター(コーディネータ、クエリルータ、プロキシとも呼ぶ)は交通整理役で、与えられたリクエストをどのシャードが処理するべきか答えます。
一般的なパターンは2つ:
- クライアントサイドルーティング: アプリのライブラリがシャードマップを保持し直接正しいシャードへ接続する。
- プロキシルーティング: アプリはルーターサービスに接続し、ルーターがリクエストを転送する。
ルーターはアプリ側の複雑さを減らしますが、適切に設計しないとボトルネックや新たな障害点になり得ます。
メタデータ/設定サービス:シャードマップ、所有権、ヘルス
シャーディングは次のようなメタデータに依存します:
- シャードマップ(どの範囲/ハッシュバケット/IDをどのシャードが所有するか)
- 所有権(マイグレーション中は所有が一時的に重複することがある)
- ヘルスとメンバーシップ(どのノードが稼働中か、プライマリ/レプリカの役割、ドレイン中か)
この情報は設定サービス(小さなコントロールプレーンDB)に置かれることが多く、メタデータが古いか不整合だと、シャード自体が健康でもルーターが誤った場所へ送ってしまいます。
バックグラウンドジョブ:バランシング、マイグレーション、バックアップ
シャーディングは時間経過で使いやすさを保つためにバックグラウンド処理に依存します:
- シャード間で成長に差がついたときの リバランシング
- 所有権を移す マイグレーション
- 多数のシャードをまたいだ バックアップ/リストア 手順
これらは初期には無視されがちですが、稼働中にシステムの形を変える点で多くの本番トラブルの原因になります。
シャードキーの選定:最初の大きなトレードオフ
シャードキーは行をどのシャードに置くか決めるフィールド(または組み合わせ)で、この一択が性能、コスト、将来の機能性に大きく影響します。シャードキーはリクエストが1つのシャードに行くか多数にファンアウトするかを制御します。
良いシャードキーの条件
良いキーは概ね:
- 高カードinality(多くの値)(例:countryより
user_id) - 均等分布:書き込み・読み取りがシャード間に広がる
- 安定したアクセスパターン:現状と次四半期の利用パターンに合っている
例:マルチテナントアプリで tenant_id をキーにすることでテナント内の読み書きが一つのシャードに収まりやすく、テナント数が多ければ負荷も分散します。
悪いシャードキーの条件とその影響
問題を招くキーの例:
- 時間ベースの単調キー(タイムスタンプ、オートインクリメント):新データが常に最新シャードに集中して書き込みホットスポットを作る
- 低カードinalityフィールド(status、plan_tier、country):値が少なく一部シャードに負荷が集中する
- 可変識別子(emailや変更可能なユーザー名):キーが変わるとデータ移動が高コストで危険
低カードinalityキーはフィルタには便利でも、ルーティング不能なクエリを多数のシャードにファンアウトさせる原因になりがちです。
実際のトレードオフ:クエリ利便性 vs 分散品質
ロードバランスに有利なシャードキーが必ずしもプロダクト側のクエリにとって最良とは限りません。
user_idに最適化すると多くのレイテンシに敏感な操作が単一シャードに収まるが、グローバルなレポーティングは遅くなるか別系統が必要になる。regionに最適化するとレポートは楽になるが、ホットスポットや不均等な容量配分のリスクが高まる。
多くのチームは主要でレイテンシに敏感な操作に合わせてシャードキーを決め、他はインデックス、デノーマライズ、レプリカ、専用の分析テーブルで補います。
よくあるシャーディング戦略(レンジ、ハッシュ、ディレクトリ)
最良の方法は一つではありません。選択肢はルーティングの容易さ、データの均等分散、アクセスパターンの弱点を形作ります。
レンジシャーディング
レンジシャーディングでは各シャードがキー空間の連続区間を所有します(例:
- シャードA: customer_id 1–1,000,000
- シャードB: customer_id 1,000,001–2,000,000 )
ルーティングは単純ですがホットスポットの問題があります。新しいユーザーに増分IDを割り当てる場合、最新のシャードが書き込みのボトルネックになります。範囲クエリ(例:10月1日〜10月31日の注文)は物理的にまとまっているため効率的に処理できるのが利点です。
ハッシュシャーディング
ハッシュシャーディングはシャードキーをハッシュ関数に通し、その結果でシャードを選びます。これによりデータがより均等に分散され、「最新シャードにすべてが行く」問題を避けやすくなります。
代償として範囲クエリが困難になります。ID X〜Y のようなクエリは少数のシャードに絞れず、多数に触れる可能性があります。
現実的な実装では一貫ハッシュを使い、シャード数が増えても全キーが大きく再配置されないように仮想ノードを配置することが一般的です。
ディレクトリ(ルックアップ)シャーディング
ディレクトリシャーディングはキー→シャードの明示的マッピングを保持します。柔軟性が高く、特定テナントを専用シャードに置く、個別に移動する、不均一なシャードサイズを許容するといった運用が可能です。
欠点は依存先が増えることです。ディレクトリが遅い、陳腐化、または利用不能になるとルーティングが破綻します。
複合キーとサブシャーディング
実際のシステムは戦略を混ぜます。複合シャードキー(例:tenant_id + user_id)はテナントを分離しつつテナント内の負荷を分散できます。サブシャーディングは類似のアプローチで、まずテナントでルートし、その内部をハッシュして大きなテナントが1つのシャードを独占しないようにします。
クエリの動き:ルーティング対スキャッター・ギャザー
シャード化されたデータベースには非常に異なる二つの「クエリ経路」があります。どちらの経路になるかを理解すれば、パフォーマンスの驚きの多くが説明できます。
単一シャードクエリ:高速経路
理想はクエリが正確に1つのシャードにルーティングされることです。リクエストにシャードキーが含まれているか、ルーターがマッピングできればシステムは直接正しいシャードに送れます。
そのためチームは一般的な読み取りを「シャードキーに気づかせる」ことに執着します。単一シャードだとネットワーク往復や協調が少なくなり、ロックや実行もシンプルです。
スキャッター・ギャザー読み取り:ファンアウトとテールレイテンシ
クエリが正確にルーティングできない場合(非シャードキーでフィルタしている等)、システムは多くのまたは全シャードにブロードキャストすることがあります。各シャードがローカルでクエリを実行し、ルーターが結果をマージ(ソート、重複除去、LIMIT適用、部分集計の合算)します。
このファンアウトはテールレイテンシを増幅します:9個のシャードが速くても1つの遅いシャードが全体を遅らせる。ユーザーの1回のリクエストがN回のシャードリクエストになるので累積負荷も増えます。
シャード間ジョインと集約
シャード間ジョインは高コストです。通常は各シャードで部分計算をしてから集約する二相計画が必要になります。
インデックスの制約:ローカル vs グローバル
多くのシステムはデフォルトでローカルインデックスを使います:各シャードが自身のデータだけをインデックスする。保守コストは低いがルーティングは助けません。
グローバルインデックスは非シャードキーでのターゲットルーティングを可能にしますが、書き込みオーバーヘッドや追加の一貫性問題を伴います。
シャード間の書き込みとトランザクション
書き込みはシャーディングが「ただのスケール手段」から設計を変える領域です。単一シャードで完結する書き込みは速く単純ですが、複数シャードに跨る書き込みは遅く失敗が起きやすく、正しく実装するのが難しくなります。
単一シャード書き込み:ハッピーパス
各リクエストが1つのシャードにルーティングされる場合(通常はシャードキーを利用)、そのシャードの通常のトランザクション機構を使えます。原子性と分離性はそのシャード内で保証され、運用上の課題は単一ノードのものと似た形になります。
複数シャード書き込み:複雑さが跳ね上がる場所
2つ以上のシャードを1つの論理操作で更新する必要が出ると(例:送金、注文の所有者移動、別の場所にある集計の更新)、分散トランザクションの領域に入ります。分散トランザクションは遅延、ネットワーク分断、再起動などにより難しく、二相コミットのようなプロトコルは追加の往復を生み、タイムアウトでブロックしたり失敗時の状態が曖昧になりがちです。
シャード越え書き込みを避けるパターン
- データローカリティ: 関連レコードを同一シャードに寄せる(例:顧客に関するすべて)
- リクエスト所有: 操作を1つのシャードが“所有”するように設計し、他は読み取りのみとする
- デノーマライズ: 小さなデータを複製して更新のファンアウトを減らす
冪等性と再試行の安全性
シャーディング環境ではリトライは不可避です。書き込みを冪等にするために、安定した操作ID(冪等性キー等)を使い、既に適用されたマーカーをDBに保存しておくと、タイムアウト後の再試行が二重課金や重複注文を生まないようにできます。
よくある質問
データベースのシャーディングとは何で、レプリケーションとどう違うのですか?
シャーディング(水平分割)は、単一の論理データセットを複数のマシン(「シャード」)に分割し、それぞれが別の行を保持する設計です。
対照的に、レプリケーションは同じデータのコピーを複数のノードに保持し、可用性や読み取りスケールの向上を主な目的としています。
なぜ単にデータベースをスケールアップしないのですか?
垂直スケーリングは単一のデータベースサーバーをより強力なマシンに移すことです。運用は単純になりがちですが、物理的な限界やコストの問題が早晩出てきます。
シャーディングはマシンを増やしてスケールアウトするアプローチですが、その代わりにルーティング、リバランシング、シャード間の整合性などの課題が生じます。
シャーディングは実際にどんな問題を解決しますか?
チームがシャーディングを選ぶのは、単一ノードが再発的にボトルネックになったときです。例えば:
- ディスクやインデックスの成長でバックアップや保守が遅くなる
- CPU/ログ書き込み/ロック競合で書き込みスループットが頭打ちになる
- 読み取り負荷がプライマリやレプリカを圧倒する
- 「ノイジーネイバー」(特定テナントやワークロード)が他を劣化させる
シャーディングはデータとトラフィックを分散させ、ノードを追加することで容量を増やします。
シャード化されたデータベースシステムのコアコンポーネントは何ですか?
典型的なシャーディングシステムは次を含みます:
- シャード: ストレージとインデックスを持つ独立したパーティション
- ルーター/コーディネータ: どのシャードに問い合わせるかを決める
- メタデータ/設定サービス: シャードマップ、所有権、ヘルス、メンバー情報
- バックグラウンド処理: リバランシング、マイグレーション、バックアップ/リストアのワークフロー
これらの要素が一貫して動かないと、パフォーマンスや正しさが損なわれます。
シャードキーとは何で、なぜ重要なのですか?
シャードキーは、どのフィールド(またはフィールドの組み合わせ)で行をどのシャードに置くかを決めるものです。これが、リクエストが単一シャードに到達するか多数にファンアウトするかを決め、将来のパフォーマンスやコストに大きく影響します。
良いシャードキーの特徴:
- 高いカードinality(多くの異なる値)(例:
user_id) - 均等な分散(書き込みと読み取りがシャード間で均等になる)
- 安定したアクセスパターン(現在と将来の主なクエリに合っている)
例えばマルチテナントでは tenant_id でシャードすることがよくあり、ほとんどの操作が同じシャード内で完結します。
どんなシャードキーが“悪い”とされ、どんな問題を引き起こしますか?
「悪い」シャードキーの例とその弊害:
- 時間ベースの単調キー(タイムスタンプやオートインクリメントID):新しいデータが常に最新のシャードに集中し、書き込みホットスポットを生む。
- 低カードinalityフィールド(ステータス、プラン、国など):値の種類が少ないと一部シャードに負荷が集中する。
- 変更されうる識別子(メールアドレスや変更可能なユーザー名):キーが変わるとデータ移動が高コストで危険になる。
これらはルーティングが曖昧になり、ルックアップが散らばる(scatter-gather)原因になります。
レンジ、ハッシュ、ディレクトリの各シャーディングは何で、いつ使うべきですか?
代表的なシャーディング戦略:
- レンジシャーディング(Range): キースペースの連続領域を各シャードが担当。ルーティングは簡単だが、単調増加や特定範囲の人気でホットスポットが発生しやすい。範囲クエリは効率的になる利点がある。
- ハッシュシャーディング(Hash): シャードキーをハッシュしてシャードを選ぶ。データ分布が均等になりやすいが、範囲クエリが複数シャードにまたがるため高価になる。追加時の再配置を抑えるために一貫ハッシュ(consistent hashing)や仮想ノードを使うことが多い。
- ディレクトリ(ルックアップ)シャーディング: キー→シャードの明示的マップを保持する方式。個別テナントを専用シャードに置けるなど柔軟だが、そのディレクトリが遅延や障害を起こすとルーティングが壊れる依存点になる。
実運用では複合キー(例:tenant_id + user_id)やサブシャーディング(まずテナントでルーティングし、その内部をハッシュする)といった混合戦略を使うことが多い。
シャード化された環境でのクエリはどのように動作しますか?
シャード化後のクエリには大きく二通りのパスがあります:
- 単一シャードクエリ(高速パス): リクエストにシャードキーが含まれるか、マップで一意にルーティングできれば一つのシャードに送られる。ネットワーク往復や協調が少なく、レイテンシが低い。
- スキャッター・ギャザー(fan-out): シャードキーで特定できないクエリは複数(あるいは全て)のシャードにブロードキャストされ、各シャードが部分結果を返し、ルーターがマージする。1つでも遅いシャードがあれば全体の遅延を引き上げる(テールレイテンシ問題)。
クロスシャードの結合や集約は二段階計算(各シャードで部分集計→マージ)が必要になり、コストが高くなります。ローカルインデックスは各シャード内で有効だが、ルーティングを助けない点に注意。グローバルインデックスはルーティングを改善できるが、書き込み負荷や一貫性の問題が増える。
シャード間での書き込みやトランザクションはどう扱いますか?
書き込みはシャーディングの苦労が最も顕著に出る領域です。
- 単一シャード書き込み(ハッピーパス): リクエストが一つのシャードにルーティングされる場合、そのシャード内で通常のトランザクション機構が使え、原子性と分離性が保たれます。
- マルチシャード書き込み: 二つ以上のシャードをまたぐ更新(例:口座振替、注文の所有者変更、外部に保存された集計の更新)は分散トランザクションの領域に入り、二相コミットのような協調が必要になります。これらはラウンドトリップが増え、タイムアウトや不確実な失敗状態(片方だけ適用された等)を招きやすいです。
回避パターン:
- データローカリティ: 関連データを同一シャードにまとめる
- リクエストルーティング: 操作を一つのシャードが“所有”するよう設計し、他は参照にとどめる
- デノーマライゼーション: 小さなデータを複製して更新のファンアウトを避ける
また、シャーディング環境ではリトライが不可避なので、書き込みを**冪等(idempotent)**にすることが重要です。操作IDや冪等キーを使い、既に適用済みマーカーを保存することで、再送による二重適用を防げます。
シャーディングとレプリケーションは整合性にどう影響しますか?
シャーディングはデータを分割しても冗長性は必要です。各シャード内でのレプリケーションは、ノード障害時の可用性を保ちますが、「今の正しい状態は何か?」を判断するのが難しくなります。
- シャード内のレプリケーション: プライマリ(リーダー)が書き込みを受け、レプリカがコピーする。プライマリ障害時はレプリカ昇格で復旧するが、レプリカは数ms〜数秒遅れることがある。
- 一貫性モデル: 強い一貫性(書き込み成功後はその更新が読める)と最終的一貫性(しばらく古いデータが返る可能性がある)のトレードオフがある。シャード内は強い一貫性を保ちつつ、シャード間では緩い保証になることが多い。
グローバルな制約(ユニーク性、外部キー、グローバルカウンタ)は難題です。例えば全体で一意にするには集中インデックスや専用の制約シャード、アプリ側の予約ワークフローが必要になることがあります。これらの選択は製品上の「正しさ」の定義に直結します。
ダウンタイムなしでのリバランシングやリシャードはどう行いますか?
リバランシングはシステムを使いやすく保つために不可欠です。データ成長やスキュー、ノード追加や廃棄に伴ってデータの場所を変える必要が出ますが、これはルーティングの変更を伴うため難易度が高い作業です。
よく使われるオンライン移行パターン(コピー→オーバーラップ→カットオーバー):
- コピー: 稼働中にソースからターゲットへバックフィルする
- デュアルライト(ときにデュアルリード): 移行期間中は新しい変更を旧・新両方に書く。読み取りは両方を参照するか「新しい方を優先」ルールを使う
- カットオーバー: シャードマップを更新してトラフィックを新しい場所へ向ける
- クリーンアップ: デュアルライトを止め、旧コピーを削除してスペースを回収する
クライアントがルーティング結果をキャッシュしていると破壊的になるため、ルーティングメタデータはバージョン管理し、頻繁にリフレッシュするよう設計する必要があります。運用上は追加負荷やキャッシュチェンジによる一時的な性能低下、ロールバック計画、観測性の確保が重要です。
ホットスポットやスキューはどう発生し、どう検出・対処しますか?
シャーディングは「均等分割」を前提とするが、実運用では見かけ上均等でも劇的に不均衡に振る舞うことがあります。
- ホットパーティション(ホットキー): セレブアカウント、人気商品、大きなバッチ処理、あるいは「今日」のような時間ベースのキーが一部のシャードにトラフィックを集中させる。
- スキュー(歪み): データサイズのスキュー(あるシャードが多くのバイトを持つ)とトラフィックスキュー(あるシャードが多くのQPSを処理する)は一致しないことがある。
検出方法:シャードごとのダッシュボード(p95 レイテンシ、QPS、ストレージ使用量等)を素早く確認する。あるシャードのレイテンシだけが上がっていればホットスポットの兆候です。
緩和策:トラフィック分散を優先するシャードキー選定、ホットキーへのバッキング/ソルト(bucketing/salting)、ホットアイテムのキャッシュ、テナントレベルのレート制限、ホットシャードの分割・移動などがあります。
シャード化されたシステムでの障害モードとデバッグはどう変わりますか?
シャーディングはサーバーの数を増やすだけでなく、故障の種類と調査対象を増やします。多くのインシデントは「データベースが落ちた」ではなく「あるシャードだけ使えない」「どこにデータがあるか合意が取れていない」といった形で現れます。
よくある障害モード:
- シャードの利用不可(クラッシュ、ディスク満杯、長いGCなど)→一部顧客だけ影響を受ける
- ルーターの誤ルーティング:設定変更やデプロイミスで間違ったシャードに送ってしまう
- メタデータの陳腐化/不整合:移行中に異なるコンポーネントが同じキーを別の場所にルーティングする
- 部分的ネットワーク障害:ルーターと一部シャード間のタイムアウトがリトライを誘発し負荷を増幅する
デバッグ手法の違い:リクエスト追跡のために相関IDを導入し、API層からルーター、シャードまで伝搬させる。分散トレーシングでどのシャードが遅いかを可視化し、メトリクスは必ずシャード単位で分解する。
データ整合性の事故例:リトライによる重複、データ移動後にルーティングが古い場所を指し続けたため行が見つからない、メタデータのスプリットブレインで二つのビューが同じキーを書き受ける等。
バックアップ/リストアとDRは「多くのパーツを正しい順序で戻す」作業になります。メタデータを先に復元し、各シャードを復元してシャード境界とルーティングが復元ポイントに一致していることを検証するリハーサルが必要です。
いつシャーディングを避けるべきで、実用的な代替手段は何ですか?
シャーディングは便利なスケーリング手段ですが、恒久的にシステムの複雑さを増すため、可能なら避けるべきです。シャード化前にまず試す価値のある選択肢:
- インデックスとクエリチューニング:遅い経路を先に改善する
- キャッシュ:読み取り重めの安定したレスポンスをキャッシュで受ける
- リードレプリカ:読み取りをオフロード(レプリカラグを許容できるなら)
- 単一ノードでのテーブルパーティショニング:テーブル分割で保守性・性能を改善する
- 古いデータのアーカイブ
シャーディングを安全に進めるには、ルーティングや冪等性、移行ワークフロー、観測性といった“配管”を本格導入前にプロトタイプするのが有効です。
例:Koder.ai のようなツールを使えば、チャットから小さな現実的サービス(管理UI+バックエンド+PostgreSQLなど)を素早く立ち上げ、シャードキーに依存するAPIや冪等キー、カットオーバー挙動をサンドボックスで試せます。スナップショットやロールバック、ソースコードエクスポートがあると、設計上の判断を本番スタックに持ち込む前に検証できます。
シャーディングが適するのは、単一ノードの限界を明確に超え、かつ重要なクエリの大半がシャードキーでルーティングできる場合です。一方でアドホックなクエリや頻繁なマルチエンティティトランザクション、グローバル一意制約が多い製品では不向きです。
短いチェックリスト:
- ワークロード: ボトルネックはCPUかI/Oかメモリかロック競合か、シャーディング以外で解決できないか?
- クエリパターン: 重要なクエリの90%+をシャードキーでルーティングできるか?
- チーム体制: シャードマップ、オンコールrunbook、シャード横断トランザクションの責任は誰が持つか?
- SLO: あるシャードの部分的劣化や長いテールレイテンシを許容できるか?
最後に、シャーディングを先延ばしにしても移行経路を設計しておくこと(将来のシャードキーをブロックしない識別子の選択、単一ノード前提をハードコーディングしないこと、最小ダウンタイムの移行手順のリハーサル)が重要です。