Redisクラスタの概要
Redisはバージョン3.0以降、ネイティブのクラスタモードをサポートしています。このモードでは、ノードの自動検出、マスター・スレーブ選択による障害耐性、およびオンラインでのシャーディング(データ分割)が可能です。Redisクラスタは、データを複数のRedisノードに自動的に分散させることで、可用性とスケーラビリティを確保します。
クラスタアーキテクチャの詳細
Redisクラスタの構成要素と動作原理は以下の通りです。
- 完全メッシュネットワーク: クラスタ内のすべてのRedisノードは互いに接続(Ping-Pongメカニズム)し、Gossipプロトコルとバイナリプロトコルを使用して情報を効率的に交換します。
- 障害検出: あるノードの故障は、クラスタ内の過半数のマスターノードがそのノードを「故障状態」と判断した場合にのみ公式に適用されます。これにより、ネットワークの分断などによる誤判定(スプリットブレインの回避)を防ぎます。通常、奇数台のノード構成が推奨されます。
- クライアント接続: クライアントはプロキシ層を介さず、Redisノードと直接通信します。クラスタ内のいずれかの利用可能なノードに接続すれば、クライアントはクラスタ全体のトポロジーを把握し、適切なノードへリダイレクトされます。
- ハッシュスロットによるデータ分割: Redisクラスタはデータを16384個のスロット(ハッシュスロット)に論理的に分割して管理します。各ノードは特定の範囲のスロットを担当し、ノード、スロット、データ値のマッピングを維持します。
ハッシュスロットの計算アルゴリズム
キーがどのスロットに割り当てられるかは、CRC16アルゴリズムによって決定されます。計算結果は常に0から16383の範囲に収まります。
以下は、クライアント側でスロットを計算するロジックの概念を示したPythonコードの例です。
import crcmod
# Redisで使用されるCRC16多項式の定義
crc16_func = crcmod.mkCrcFun(0x11021, initCrc=0, xorOut=0, rev=False)
def get_redis_slot(key: str) -> int:
"""
キー名からRedisクラスタのハッシュスロットを計算します。
"""
# CRC16計算を実行
crc_value = crc16_func(key.encode('utf-8'))
# 16384 (0x3FFF) でANDを取ることでスロット範囲に収める
return crc_value & 16383
# 検証例
sample_keys = ["user:1001", "product:detail", "session_token"]
for k in sample_keys:
slot = get_redis_slot(k)
print(f"Key: {k} -> Slot: {slot}")
マスターノードに障害が発生した場合、そのノードが担当していたスロットはレプリカ(スレーブ)ノードによって引き継がれ、サービスの継続性が保たれます。なお、新規ノードを追加する際、スロットを割り当てない限りそのノードはデータを保持できません。運用には適切なスロットの再配布(Resharding)が必要です。
クラスタ環境の構築
高可用性を実現するためには、少なくとも3つのマスターノードとそれぞれに対応するスレーブノード、計6ノードでの構築が推奨されます。過半数のマスターノードが生存している必要があるため、ノード数は奇数にするのが一般的です。
事前準備と依存関係
Redis 5.0以前では、クラスタ管理ツールであるredis-trib.rbを実行するためにRuby環境が必要でしたが、Redis 5.0以降ではredis-cliにクラスタ管理機能が統合されており、Rubyの依存は不要です。
設定ファイルの構成
ここでは、異なるポート(例:7000, 7001...)で複数のインスタンスを起動する場合の設定例を示します。各インスタンスのredis.confを以下のように変更します。
# ポート番号の設定(ノードごとに変更)
port 7000
# 外部からの接続を許可
bind 0.0.0.0
# クラスタモードの有効化
cluster-enabled yes
# クラスタ状態の保存ファイル(ノードごとに一意にする)
cluster-config-file nodes-7000.conf
# ノードタイムアウト時間(ミリ秒)
cluster-node-timeout 5000
# 永続化設定(AOF)
appendonly yes
# 認証設定(クラスタ内通信とクライアント接続)
masterauth your_strong_password
requirepass your_strong_password
クラスタの起動と作成
設定ファイルの編集後、すべてのRedisインスタンスを起動し、クラスタを初期化します。Redis 5.0以降のコマンドを使用する場合、以下のように実行します。
# Redisインスタンスの起動
redis-server /path/to/redis-7000.conf
redis-server /path/to/redis-7001.conf
# ... 他のノードも同様に起動
# クラスタの作成(レプリカ1台ずつの場合)
redis-cli --cluster create \
192.168.1.10:7000 192.168.1.10:7001 192.168.1.10:7002 \
192.168.1.10:7003 192.168.1.10:7004 192.168.1.10:7005 \
--cluster-replicas 1 \
-a your_strong_password
コマンド実行時、ハッシュスロットの自動割り当てに関する確認が表示されます。これに同意するとクラスタが構築されます。通常、スレーブノードはスロットを保持せず、マスターノードの障害時に待機状態となります。
クラスタ運用管理コマンド
構築後のクラスタ管理には、以下のようなコマンドを使用します。なお、クラスタ操作を行う際は-cオプション(クラスタモード)を指定します。
クラスタ状態の確認
# クラスタ全体の状態とスロット割り当てを確認
redis-cli -c -p 7000 -a your_strong_password cluster nodes
ノードの追加(マスター)
新しいマスターノードをクラスタに参加させるには、add-nodeコマンドを使用します。
# 新ノード(7006)を既存クラスタ(7000)に追加
redis-cli --cluster add-node 192.168.1.10:7006 192.168.1.10:7000 -a your_strong_password
追加しただけではスロットが割り当てられていないため、reshardコマンドでデータの移行を行う必要があります。
ノードの追加(スレーブ)
特定のマスターに対してスレーブを追加する場合、マスターのノードIDを指定します。
# 新ノード(7007)を特定のマスターのスレーブとして追加
redis-cli --cluster add-node \
--cluster-master-id <master_node_id> \
192.168.1.10:7007 192.168.1.10:7000 \
-a your_strong_password
マスターIDを省略した場合、Redisはレプリカ数が少ないマスターに対して自動的に割り当てを行います。
ノードの削除
ノードを削除するには、削除対象のノードIDを指定します。削除可能なのは、スレーブノード、またはスロットが割り当てられていない空のマスターノードのみです。
# ノードIDを指定して削除
redis-cli --cluster del-node 192.168.1.10:7000 <target_node_id> -a your_strong_password
スロットの再配布(Resharding)
ノード数の増減に伴い、データの再配置を行うにはreshardコマンドを使用します。対話型のプロンプトが表示され、移動するスロット数や移動元・移動先のノードを指定します。
# 再配布ウィザードの開始
redis-cli --cluster reshard 192.168.1.10:7000 -a your_strong_password