98. キー空間は16,384のスロットに切られている — ハッシュで住所を決める水平分割の再登場
1台のサーバーに収まらなくなったキャッシュを、Valkey/Redis OSS のクラスターモードがどう分割するのか——キー→スロット→シャードという住所の決め方を、図で追っていきます。
① シャードの中身は階層
- 公式: "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: "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スロットという目盛り
- 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枚挟むのがこの設計の肝です。
④ なぜスロットを挟むのか
- スロット数(16,384)は固定なので、キー→スロットの対応は永久に不変。
- DynamoDB編で触れたコンシステントハッシュ——ノードの増減で再配置を最小化する——と全く同じ問題意識。スロットはその「間接層」の具体的な実装。
スロット数(16,384)は固定なので、キー→スロットの対応は永久に不変。シャードを増減しても動かすのは「スロットをどのシャードに割り当てるか」だけで、キー全部の再計算は起きません。これは DynamoDB編で触れたコンシステントハッシュ——ノードの増減で再配置を最小化する——と全く同じ問題意識で、スロットはその「間接層」の具体的な実装です。
⑤ スケールはスロットの引っ越し
- オンライン処理: "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) ..."
スケールアウト/インの実体は「スロットの引っ越し」であり、リクエストを受けながら実行できます。削除時は「残るシャードに全データが収まるか」を先に確認し、収まらなければ中止して元の構成を守る——分割の単位がスロットだからこそ成り立つ安全策です。
⑥ 使い分けと同型の再登場
- 読み負荷: "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 のシャードは、どれも「ハッシュで住所を決めて水平に分ける」という全く同じ問いに同じ形で答えています——キャッシュでも原理は同型で、名前が違うだけです。