Redis Clusterの深淵:ハッシュスロットが導く「スケールの設計思想」
Redisを単なる「高速なKVS」として使っているうちは、まだ初級者だ。
真のエンジニアがRedisを語る時、それは「分散データストアとしての極限の可用性と線形スケーラビリティ」を指す。
今日は、Redis Clusterの心臓部である「ハッシュスロット」の仕組みから、実務で絶対に陥ってはならない落とし穴まで、現場の知見を叩き込む。
—
1. ハッシュスロット:分散の「最適解」
Redis Clusterが16,384個という固定されたスロットを持つ理由は、単なる気まぐれではない。
- なぜ 16,384 なのか?
- ノード間通信(Gossipプロトコル)のオーバーヘッドと、データ分散のバランスが最も取れる数値だからだ。1,000ノード程度までなら、ビットマップのサイズも通信量も許容範囲内に収まる。
- 数学的な美しさ
- `CRC16(key) mod 16384`。この単純な計算が、クラスタ内のどこにデータがあるかを決定づける。この決定論的なルーティングこそが、中央集権的なプロキシを不要にし、クライアントサイドでの直接アクセスを可能にしている。
【設計の勘所】
「ハッシュタグ `{}` 」を使いこなせ。`user:{100}:profile` と `user:{100}:settings` は、ハッシュタグを使うことで確実に同じスロットに配置される。トランザクションやマルチキー操作が必要なデータは、この仕組みで「論理的な局所性」を強制せよ。
—
2. リシャーディング:止まらない拡張の裏側
「負荷が増えたからノードを追加しよう」――この時、Redis Clusterで行われるのはデータの移動(リシャーディング)だ。
ここでの鉄則は一つ:「移行中も読み書きを止めない」こと。
移行中のキーには `MIGRATING` や `IMPORTING` という状態が付与され、クライアントには `-ASK` リダイレクトが返る。
【実務上の鉄則】
リシャーディングは、ネットワーク帯域とCPUリソースを食う。ピークタイムにリシャーディングを走らせるような愚行は避けろ。ノード追加は、事前に監視ツールで「負荷の低い時間帯」を特定した上で行うのがプロの所作だ。
—
3. 可用性の神話と、実務的な設計パターン
Redis Clusterは「マスター・スレーブ構成」を内包している。自動フェイルオーバーは魔法ではない。
- Failoverのロジック
- 半数以上のマスターがノードのダウンを合意(`PFAIL` → `FAIL`)した瞬間に、スレーブがマスターに昇格する。
- ここで重要なのは、「ネットワーク分断(Split-Brain)」の回避だ。最低でも3マスター、各マスターに1スレーブの計6ノードが、可用性を担保するための最低限の「スタートライン」である。
【堅牢な設計への提言】
「Redis単体で永続化を完璧にしようとするな」。
Redisはあくまで高速なデータストアだ。重要なビジネスデータは必ずRDB(MySQL/PostgreSQL)をSource of Truthとし、Redisには「TTL付きのキャッシュ」あるいは「最新状態の投影」を置く。フェイルオーバーでデータが数ミリ秒飛ぶ可能性を許容できない設計は、Redis以前の問題だ。
—
4. パフォーマンスを殺す「悪手」
コードレビューでよく見かける、システムを崩壊させるアンチパターンを挙げる。
① `KEYS` や `SCAN` の乱用
クラスタ環境で全ノードを横断して `KEYS ` を叩くのは自殺行為だ。`SCAN` を使う場合も、ハッシュスロットを意識してノードごとに叩く必要がある。基本は「インデックス用のキーを別途持つ」のが正解だ。
② クライアントの再接続コスト
悪い例: リクエストごとに接続を確立する
def get_data(key):
r = redis.RedisCluster(startup_nodes=nodes) # 毎回インスタンス生成
return r.get(key)
これでは、接続確立のオーバーヘッドでRedisの高速性は打ち消される。
「コネクションプール」を使い、接続を維持せよ。 クライアントライブラリは、クラスタのトポロジー(スロットマップ)をキャッシュしているはずだ。これを頻繁に再構築させる設計はパフォーマンスを著しく低下させる。
—
最後に:アーキテクトとしての助言
Redis Clusterは非常に強力だが、「複雑性」というコストを支払うことになる。
あなたが開発しているシステムが、本当に「単一Redisのメモリ上限」を超えるのか? 「書き込み負荷が単一マスターの限界を超える」のか?
もし答えが No なら、まずはシンプルな「レプリケーション構成」や「プロキシを用いた構成(TwemproxyやEnvoy)」を検討すべきだ。「必要のない分散」は、システムの障害ポイントを増やすだけの最大の足枷になる。
それでもスケールが必要な時、Redis Clusterはその要求を最高レベルで応えてくれるはずだ。その時、この記事で語った「スロット」と「リシャーディング」の挙動を思い出してほしい。
設計は、妥協ではなく選択の連続だ。健闘を祈る。
コメント