TL

シャッフルシャーディングの確率論

1テナントの暴走で全顧客が道連れになる事故を、ワーカを重複割当するだけで桁違いに減らせる。なぜ効くのかを重複組合せ数の確率計算から導き、AWSが多用する隔離設計の勘所まで解説。

応用シャッフルシャーディング障害分離確率論組合せ論マルチテナント可用性最終更新: 2026-06-21
TL;DR要点だけ先に
  • 1.シャッフルシャーディングは各テナントにワーカ集合からランダムにk台を割り当てる。2テナントが「全k台とも一致して完全に巻き込まれる」確率は重複組合せ数の比 C(n-k,k)/C(n,k) で決まり、nとkが少し増えるだけで激減する。
  • 2.毒テナント1人が他テナントを完全に巻き込む割合は、k=2でも数百分の一、k=3〜4にすると数千〜数万分の一に落ちる。完全分離(テナントごと専有)の高コストなしに、ほぼ分離に近い隔離が得られる。
  • 3.肝は「重なってもkのうち一部だけ」なら被害テナントは残りの健全ワーカで生き延びる点。リトライやヘルスチェックで毒ワーカを避ける仕組みと組み合わせて初めて確率論どおりの隔離効果が出る。

なぜ普通のシャーディングでは足りないのか

マルチテナントなサービスで、n台のワーカ(サーバー)を用意し、各テナントを一部のワーカへ振り分ける状況を考えます。狙いは 障害分離(blast radius の限定) です。あるテナントが「毒」になったとき(壊れたリクエストでワーカをクラッシュさせる、リトライ嵐でCPUを焼く、など)、その毒が割り当て先のワーカにしか及ばないようにしたい。

素朴な方法は、n台をいくつかの 固定シャード に分割し、各テナントを1つのシャードに割り当てることです。例えばn=8台を4台ずつ2シャードに割れば、毒テナントは自分のシャード4台だけを壊し、もう片方の4台にいるテナントは無傷で済みます。

# 固定シャード方式(2シャード)
シャードA: [w1 w2 w3 w4]   ← テナント群A(毒テナントもここ)
シャードB: [w5 w6 w7 w8]   ← テナント群B(無事)

問題は、同じシャードに同居したテナントは運命共同体 になる点です。シャードAに100テナントいれば、毒テナント1人がそのシャードを落とした瞬間、残り99テナントが全滅します。シャード数を増やせば各シャードのテナント数は減りますが、シャードあたりのワーカも減るので冗長性が落ちる。「巻き込まれる人数」と「1テナントが使える台数」がトレードオフになり、固定分割だけでは両立できません。

目標は「完全一致」を稀にすること

シャッフルシャーディングの発想は、テナントどうしの割り当てを完全には一致させないことにあります。2人のテナントがワーカを1台も共有しなければ、片方の毒はもう片方に届きません。たとえ何台か共有しても、共有していない健全なワーカが残っていれば被害テナントは生き延びられる。つまり「割り当て集合がまるごと一致するテナントの組」をどれだけ減らせるかが勝負になります。

シャッフルシャーディングの割り当て

シャッフルシャーディング(shuffle sharding)は、固定シャードを捨て、テナントごとに n台の中から重複なく k台を選ぶ。選び方はテナントIDのハッシュを乱数の種にした擬似ランダムで、同じテナントなら毎回同じ k台になります(決定的)。

# テナントごとに毎回同じ k台を選ぶ(決定的シャッフル)
def shard_for(tenant_id, all_workers, k):
    rng = seeded_rng(hash(tenant_id))   # テナントIDで種を固定
    return rng.sample(all_workers, k)   # n台から重複なくk台を選ぶ

選べる「シャード」の総数は、n台からk台を選ぶ 組合せ数 C(n, k) 通りです。固定シャード方式が n/k 個のシャードしか持てなかったのに対し、シャッフルシャーディングは指数的に多い仮想シャードを持てる。n=100、k=5 なら C(100,5) は約 7500万通り。これだけ選択肢があれば、2人のテナントが偶然まったく同じ5台を引く確率はごく小さくなります。これが効果の源泉です。

完全一致の確率を組合せ論で出す

毒テナントを1人固定し、その k台が決まっているとします。別のテナントが、毒テナントの k台と完全に一致する集合を引く確率 を求めます。

別テナントの集合も n台からk台の一様ランダム。全パターンは C(n, k) 通り。そのうち「毒テナントと完全一致」は ちょうど1通り なので、

# 2テナントの割り当てが完全一致する確率
P(完全一致) = 1 / C(n, k)

しかし本当に怖いのは「完全一致」だけではありません。実務上の関心は 「毒テナントの k台にどれだけ重なるか」 の分布です。被害テナントが毒テナントと j台を共有する確率は、毒の k台から j台を選び、残りを毒以外の n−k台から k−j台選ぶので、超幾何分布になります。

# 被害テナントが毒テナントと ちょうど j台 共有する確率(超幾何分布)
P(共有=j) = C(k, j) * C(n-k, k-j) / C(n, k)

この式から「1台も共有しない(j=0、つまり毒の影響をまったく受けない)」確率が読めます。

# 毒テナントと1台も共有しない確率
P(共有=0) = C(n-k, k) / C(n, k)
数値で実感する

n=100、k=2 とすると、毒以外の98台から2台を引く C(98,2)=4753、全体 C(100,2)=4950。よって1台も共有しない確率は 4753/4950 ≒ 0.960。逆に言えば何らかの形で重なるテナントは約4%。さらに2台とも一致(完全巻き込み)は 1/C(100,2)=1/4950 ≒ 0.0002、つまり約5000人に1人。k=2 でさえ、完全に道連れになる相手はこれだけ稀になります。

なぜ「一部重なり」は致命傷にならないのか

ここが確率論を実利に変える要点です。被害テナントが毒テナントと j台共有していても、j が k 未満なら、共有していない k−j台は健全 です。被害テナントのリクエストが健全ワーカにも振られ、かつクライアントが毒ワーカを避けてリトライできるなら、被害テナントは生き延びます。

# k=4 のとき、毒テナントとの共有台数ごとの生死
共有 0台 : 健全4台 → 完全に無傷
共有 1台 : 健全3台 → ほぼ無傷(毒1台を避ければよい)
共有 2台 : 健全2台 → 縮退するが稼働継続
共有 3台 : 健全1台 → 綱渡り(リトライ次第)
共有 4台 : 健全0台 → 完全巻き込み(これだけが致命)

したがって本当に避けたいのは 共有=k(完全巻き込み) だけ。その確率 1/C(n,k) を小さくすればよく、k を1つ増やすだけで C(n,k) が跳ね上がるため、効果は劇的です。

n(ワーカ総数)k(1テナントの台数)完全一致 1/C(n,k)完全巻き込みの目安
10021/4950約5千人に1人
10031/161700約16万人に1人
10041/3921225約392万人に1人
10051/75287520約7500万人に1人

k を 2 から 5 にするだけで、完全に道連れになる確率は約5000分の1から7500万分の1へ、1万倍以上改善します。テナント専有(完全分離)はワーカ数がテナント数に比例して必要になり非現実的ですが、シャッフルシャーディングは固定 k台のコストで「ほぼ分離」に迫れる。これが 負荷分散アルゴリズム の上に薄く乗せるだけで効く理由です。

毒テナントが複数いるとき・前提条件

確率はテナント数が増えると効きが鈍ります。毒が1人でなく、テナント全体に占める「ある被害テナントを完全に巻き込みうる毒の組」を考えると、被害が出る期待値はテナント数 m とともに増えます。ざっくり、ランダムな2テナントが完全一致する確率が 1/C(n,k) なので、m テナントの中で完全一致ペアが現れる期待数は概ね m^2 / (2 * C(n,k)) 程度。m が C(n,k) の平方根を超えると衝突が現実味を帯びます(誕生日問題と同じ構造)。だからこそ k と n は、想定テナント数 m に対して C(n,k) が m の二乗を十分上回るよう選びます。

確率論が成立する前提を外すと隔離は崩れる

式が保証するのは「割り当ての重なりの少なさ」だけです。実際の隔離には次が必須です。(1) クライアントまたはロードバランサが、毒ワーカ(タイムアウト・エラーを返すワーカ)を検知して残りの健全ワーカへ振り直せること。これがないと共有1台でも巻き込まれます。(2) リトライが健全ワーカへ偏るための適切なヘルスチェックと、暴走を増幅しない制御。リトライ嵐はむしろ毒を全ワーカへ広げます(リトライ予算と増幅 を参照)。(3) テナント間で共有状態(同一DB・同一キャッシュ)を持たないこと。共有資源があればワーカを分けても毒はそこを通って伝播します。

実務での位置づけ

シャッフルシャーディングは AWS が Route 53 や API ゲートウェイ系のサービスで採用し、Route 53 では各顧客ドメインを4台の権威ネームサーバーへ割り当てる際にこの方式を使うことで、1顧客へのDDoSが他顧客の名前解決を巻き込まないようにしています。考え方は L7ロードバランサ、コネクションプール、キューのワーカ群、レートリミッタのバケットなど、「テナント × リソース集合」の割り当てがある場所すべて に応用できます。

毒テナントそのものを止める仕組み(アダプティブな負荷遮断 など)と組み合わせると、「毒の影響を狭い集合に閉じ込め、その集合内でも遮断で被害を最小化する」二段構えになります。シャッフルシャーディングは確率で 巻き込まれる相手の数を減らす 設計、負荷遮断は 巻き込まれた後の被害を減らす 設計で、役割が補完的です。

まとめ

  • 固定シャードはシャード内テナントが運命共同体になる。シャッフルシャーディングはテナントごとに n台から k台を決定的ランダムに選び、選択肢を C(n,k) 通りへ広げて完全一致を稀にする。
  • 2テナントが完全一致する確率は 1/C(n,k)、共有台数の分布は超幾何分布 C(k,j)*C(n-k,k-j)/C(n,k) で表せる。k を1増やすだけで C(n,k) が跳ね上がり、完全巻き込み確率が桁で下がる。
  • 致命的なのは共有=kの完全巻き込みだけ。一部重なりは健全ワーカが残るため、リトライで毒ワーカを避ければ生き延びられる。
  • 確率の前提は「毒ワーカを避けて健全ワーカへ振り直せること」と「共有資源を持たないこと」。これが崩れると式どおりの隔離は得られない(リトライ予算と増幅メタステーブル障害 も併読)。
  • テナント数 m に対し C(n,k) が m の二乗を十分上回るよう n・k を選ぶ(誕生日問題の構造)。完全分離の高コストなしに、ほぼ分離に迫る隔離が得られる。

DevOps/インフラ Article

シャッフルシャーディングの確率論を実務で読む

TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。

解決すること

シャッフルシャーディング

比較で見る軸

難易度: advanced / カテゴリ: DevOps/インフラ / タグ数: 6

導入後に効く点

毒テナント1人が他テナントを完全に巻き込む割合は、k=2でも数百分の一、k=3〜4にすると数千〜数万分の一に落ちる。完全分離(テナントごと専有)の高コストなしに、ほぼ分離に近い隔離が得られる。

先に潰すリスク

用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。

数字・仕様の読み方
難易度
advanced
カテゴリ
DevOps/インフラ
タグ数
6

判断チェックリスト

  • 自社の用途が「シャッフルシャーディング / 障害分離」に近いか確認する。
  • 強みである「シャッフルシャーディングは各テナントにワーカ集合からランダムにk台を割り当てる。2テナントが「全k台とも一致して完全に巻き込まれる」確率は重複組合せ数の比 C(n-k,k)/C(n,k) で決まり、nとkが少し増えるだけで激減する。」が本当に評価軸になるか確認する。
  • 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
  • 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
  • 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
  • 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。

次に確認する観点

シャッフルシャーディング障害分離確率論組合せ論マルチテナントシャッフルシャーディング障害分離確率論