Dev Study
AWSサービスの内部原理 コース

98. キー空間は16,384のスロットに切られている — ハッシュで住所を決める水平分割の再登場

1台のサーバーに収まらなくなったキャッシュを、Valkey/Redis OSS のクラスターモードがどう分割するのか——キー→スロット→シャードという住所の決め方を、図で追っていきます。

① シャードの中身は階層

シャードAPI/CLIでは node group
レプリケーション(複製を流す)
プライマリ読み書き両方を受ける唯一のノード
レプリカ読み取り専用
レプリカ読み取り専用
レプリカ読み取り専用
最大5つまで
  • 公式: "Within a shard, one node functions as the read/write primary node. All the other nodes in a shard function as read-only replicas."
  • レプリカ数は 0〜5(比較表の "Read replicas: 0 to 5 per shard"。APIではシャードごとの台数を NodeGroupConfiguration の ReplicaCount フィールドで指定する)。
  • レプリカが0でノードが障害を起こすと、そのシャードのデータは全損する。"If you have no replicas and a node fails, you experience loss of all data in that shard."

1つのシャードは「書き込みを受ける唯一のプライマリ + 読み取りを肩代わりする最大5つのレプリカ」という階層。この「1つの書き込み口 + 読み取りの複製」という形は、DynamoDB編・S3編・メッセージング編で繰り返し出てきた「書き込みは1点に集約し、読みは複製で広げる」という同じ発想の再登場です。

② 縦に太らせるか横に並べるか

CMD(無効)シャードは常に1つ
縦スケール: 大きいノードに変える+レプリカ最大5
各シャードが独立した書き込みエンドポイント
CME(有効)シャードを横に並べてデータを分割
シャード数 1〜最大500
shard 1
shard 2
shard 3
shard N
  • CMD: "A ... (cluster mode disabled) cluster always has a single shard with up to 5 read replica nodes." 全データが1ノードに収まる必要がある。
  • CME: "has up to 500 shards with 1 to 5 read replica nodes in each."(同ページの比較表では "0 to 5 per shard" — レプリカ0構成も可能)
  • 500上限は Valkey/Redis OSS 5.0.6 以上。"For versions below 5.0.6, the limit is 250 per cluster."(クラスターあたりのノード上限)
  • 例: 500ノードのクラスターは「83シャード(各1プライマリ+5レプリカ)」から「500シャード(各プライマリ1・レプリカ0)」の範囲で構成できる。

CMD はシャードが常に1つなので「縦に太らせる(大きいノード・レプリカ追加)」しか手がなく、全データが1ノードに収まる必要があります。CME はシャードを横に最大500個並べてデータそのものを分割できる——1台に収まらないデータをどう扱うかへの答えが、この「横に並べる」です。

③ 16,384スロットという目盛り

全キーどんな文字列キーでも
連続区間で各シャードに割り当て(startkey-endkey 形式)
キースロット0〜16,383 の 16,384個の目盛り
shard 10-3999
shard 24000-7999
shard 38000-11999
shard 412000-16383
  • Slots フィールドの公式定義: "A string that specifies the keyspace for a particular node group. Keyspaces range from 0 to 16,383. The string is in the format startkey-endkey. Example: '0-3999'."
  • この区間は API の NodeGroupConfiguration の Slots フィールドにそのまま現れる。
  • キー→スロットの対応は Valkey/Redis OSS 本体のハッシュスロット仕様 "HASH_SLOT = CRC16(key) mod 16384"(執筆時に valkey.io のクラスター仕様で確認。AWSドキュメント側は 0〜16,383 のキー空間と startkey-endkey 形式を規定しており矛盾なし)。

キーは必ず 0〜16,383 のスロットのどれか1つに対応し、各シャードはスロットの連続区間(0-3999 のような startkey-endkey)を担当します。キーとシャードの間に「スロット」という固定数の間接層を1枚挟むのがこの設計の肝です。

④ なぜスロットを挟むのか

素朴なハッシュhash(key) mod シャード数
シャード数が変わると割る数が変わる
シャード増減で動くのは
スロットを挟むkey → CRC16 mod 16384 → スロット(永久に不変)
スロット付け替えスロット→シャードの割り当てだけ動かす
個々のキーのハッシュ計算はやり直さない
  • スロット数(16,384)は固定なので、キー→スロットの対応は永久に不変。
  • DynamoDB編で触れたコンシステントハッシュ——ノードの増減で再配置を最小化する——と全く同じ問題意識。スロットはその「間接層」の具体的な実装。

スロット数(16,384)は固定なので、キー→スロットの対応は永久に不変。シャードを増減しても動かすのは「スロットをどのシャードに割り当てるか」だけで、キー全部の再計算は起きません。これは DynamoDB編で触れたコンシステントハッシュ——ノードの増減で再配置を最小化する——と全く同じ問題意識で、スロットはその「間接層」の具体的な実装です。

⑤ スケールはスロットの引っ越し

稼働中クラスターリクエストを受けながら実行できる
実体はどれも
Scale out既存のスロットを一部、新シャードへ移す
新シャードのノード数 = 既存で最小のシャードと同じ
Scale in削除シャードのスロットを残るシャードへ配り直す
収まらなければ中止 = 元の構成のまま
Rebalanceスロットをできるだけ均等に配り直す
スロットの引っ越しキースロットをシャード間で移す操作
  • オンライン処理: "your cluster can continue to serve requests even while scaling or rebalancing is in process"
  • Scale in の事前チェック: 残るシャードに全データが収まるか確認し、収まらなければ中止。"If the data won't fit ... the process is terminated"
  • Rebalance: "Move the keyspaces among the shards ... as equally distributed among the shards as possible"
  • 巨大アイテムの例外: シリアライズ後 256MB を超えるアイテムを含むキーは、scale-out/rebalance 時に新シャードへ移動されない(シャードが不均等になりうる)。scale-in 時はそのキーを含むシャードが削除されない。"If any of the keys in a shard contain a large item (items greater than 256 MB after serialization) ..."

スケールアウト/インの実体は「スロットの引っ越し」であり、リクエストを受けながら実行できます。削除時は「残るシャードに全データが収まるか」を先に確認し、収まらなければ中止して元の構成を守る——分割の単位がスロットだからこそ成り立つ安全策です。

⑥ 使い分けと同型の再登場

主負荷はどっち?
後者は他サービスと同じ問い、同じ形
CMD+レプリカ読み取り口を増やす(最大5)
書き込み口は1つのまま
CME+シャード独立した書き込みエンドポイントが増える
スナップショットもシャードごとに1つの .rdb
どれも答えは
DynamoDBパーティション(キーのハッシュ)
Kinesisシャード(キーのハッシュ)
ElastiCacheシャード(CRC16→スロット)
水平分割ハッシュで住所を決めて水平に分ける — 名前が違うだけ
  • 読み負荷: "If the primary load ... is applications reading data, you can scale ... by adding and deleting read replicas"
  • 書き負荷: "you can benefit from the additional write endpoints of a ... (cluster mode enabled) cluster"
  • スナップショットはシャードごとに1つの .rdb ファイル("creating a unique .rdb file for each shard")

読み負荷なら CMD でレプリカ、書き負荷・大容量なら CME でシャード(=書き込みエンドポイント)を増やす、が使い分けの軸。そして DynamoDB のパーティション、Kinesis のシャード、ElastiCache のシャードは、どれも「ハッシュで住所を決めて水平に分ける」という全く同じ問いに同じ形で答えています——キャッシュでも原理は同型で、名前が違うだけです。

公式ドキュメントで詳しく ↗