Redis は、オープンソースのインメモリ データ構造ストレージ システムであり、その優れたパフォーマンスと豊富なデータ構造により業界で広く認知されています。ただし、大量のデータや同時リクエストが多い場合、単一の Redis インスタンスではニーズを満たすことができない場合があります。このとき、Redis のクラスターモードを使用する必要があります。クラスター モードにより、データの可用性と信頼性が向上し、システムのパフォーマンスとスケーラビリティが向上します。次の記事では、Redis クラスターの基本概念と、Redis クラスターの動作原理、フェイルオーバー、拡張について詳しく紹介します。
記事ディレクトリ
1. Redis クラスターモードの概要
1.1. Redis クラスターモードの概要
Redis クラスター モードは Redis が提供する分散ソリューションであり、Sentinel は高可用性の問題を解決し、クラスターは高可用性と分散の問題を一挙に解決する究極のソリューションです。クラスター モードでは、データが複数の Redis ノードに分散され、各ノードがデータベース全体の一部を格納する役割を担います。この方法はデータ シャーディングと呼ばれます。
Redis Cluster は一貫したハッシュを使用しませんが、ハッシュ スロットの概念を導入します。Redis クラスターには 16384 のハッシュ スロットがあります。キーと値のペアを Redis クラスターに配置する必要がある場合、Redis は最初にキーに対して CRC16 計算を実行し、次に 16384 の残りを取得します。結果は、キーを配置する必要があります。
各 Redis ノードはハッシュ スロットの一部を担当します。たとえば、3 つのノードを持つ Redis クラスターでは、ノード A がハッシュ スロット 0 ~ 5500 を担当し、ノード B がハッシュ スロット 5501 ~ 11000 を担当し、ノードC は 11001- ハッシュ スロット 16383 を担当している可能性があります。
このようにして、キーにアクセスする必要がある場合 (読み取り、書き込み)、Redis クラスターはキー名に基づいてハッシュ スロット番号を計算し、ハッシュ スロットを担当するノードを見つけます。
Redis クラスターはマスター/スレーブ レプリケーション モードをサポートしており、各ノードには 0 個以上のスレーブ ノードがあり、データはマスター ノードからスレーブ ノードにコピーされます。マスター ノードがダウンした場合、スレーブ ノードがマスター ノードに昇格し、サービスを提供し続けることができます。
Redis クラスターは高可用性と分散機能を提供しますが、クライアントはそれを使用するときに、クロスノード トランザクションや Lua スクリプトを処理するときや、ノードの追加や削除時にハッシュ スロットを再配布するときなど、ある程度の複雑さを必要とします。
1.2. Redis クラスターの仮想スロット パーティション
分散ストレージでは、データ セットはパーティショニング ルールに従って複数のノードにマップされる必要があります。一般的なデータ パーティショニング ルールには、ノード残余パーティショニング、コンシステント ハッシュ パーティショニング、および仮想スロット パーティショニングの 3 つがあります。
ノード剰余パーティショニング (モジュロ パーティショニング): この方法は、剰余を取得することによってデータを異なるノードにマップします。たとえば、ユーザー ID の係数とノード数を取得し、対応するノードにデータを保存できます。この方法の利点は、実装が簡単で、データ分布が比較的均一であることです。ただし、ノードの数が変わると、ほとんどのデータを再割り当てする必要があり、その結果、大量のデータ移行が発生します。
Consistent Hashing Partitioning: この方法では、一貫したハッシュ アルゴリズムを通じてデータをさまざまなノードにマッピングします。一貫したハッシュ アルゴリズムの利点は、ノードの数が変わったときに、ハッシュ リング上のデータのごく一部のみを移行する必要があるため、データ移行のコストが大幅に削減されることです。同時に、一貫したハッシュ アルゴリズムにより、比較的均一なデータ分散も保証されます。
たとえば、下の図では、Key1 と Key2 は Node1 に分類され、Key3 と Key4 は Node2 に分類され、Key5 は Node3 に分類され、Key6 は Node4 に分類されます。
しかし、それでも問題はあります: キャッシュ ノードがリング上に不均一に分散されているため、一部のキャッシュ ノードに大きな負荷がかかります。ノードに障害が発生すると、このノードが負担しなければならないすべてのアクセスが別のノードに移動されます。次のノードに。
仮想スロット パーティショニング: この方法では、データ スペースを複数の仮想スロットに分割し、これらの仮想スロットを異なるノードにマップします。Redis Cluster は、すべてのキー スペースを 16384 の仮想スロットに分割する仮想スロット パーティショニング方式を使用します。この方法の利点は、ノードの数が変わったときに、データではなく仮想スロットのみを再割り当てする必要があるため、データ移行のオーバーヘッドが軽減されることです。同時に、仮想スロットのパーティショニングにより、比較的均一なデータ分散も確保できます。
1.3. Redis クラスターでよく使用されるコマンド
以下は、Redis クラスターで一般的に使用されるコマンドの一部です。
CLUSTER ADDSLOTS <slot> [slot ...]
: 現在のノードに 1 つ以上のスロットを追加します。CLUSTER COUNT-FAILURE-REPORTS <node-id>
: 他のノードから指定したノードへの障害レポートの数を返します。CLUSTER COUNTKEYSINSLOT <slot>
: 指定されたスロット内のキーと値のペアの数を返します。CLUSTER DELSLOTS <slot> [slot ...]
: 現在のノード上の 1 つ以上のスロットを削除します。CLUSTER FAILOVER [FORCE|TAKEOVER]
: フェイルオーバーを手動でトリガーします。FORCE
または が指定されている場合TAKEOVER
、他のノードからの承認を待つ必要はありません。CLUSTER FLUSHSLOTS
: 現在のノードのスロット情報をすべて削除します。CLUSTER FORGET <node-id>
:クラスタからノードを削除します。CLUSTER GETKEYSINSLOT <slot> <count>
: 指定されたスロット内のいくつかのキーを返します。CLUSTER INFO
: クラスタ情報を返します。CLUSTER KEYSLOT <key>
: リターンキーをどのスロットに配置するか。CLUSTER MEET <ip> <port>
: 新しいノードをクラスターに追加します。CLUSTER NODES
: クラスター内のすべてのノードに関する情報を返します。CLUSTER REPLICATE <node-id>
: 現在のノードを指定したノードのスレーブノードとして設定します。CLUSTER RESET [HARD|SOFT]
:現在のノードをリセットします。CLUSTER SAVECONFIG
: ノードの構成をディスクに保存します。CLUSTER SET-CONFIG-EPOCH <epoch>
: ノードの構成エポックを設定します。CLUSTER SETSLOT <slot> <subcommand> [node-id]
:スロットのステータスを設定します。CLUSTER SLAVES <node-id>
: 指定されたノードのすべてのスレーブ ノードを返します。CLUSTER SLOTS
: クラスター内のすべてのスロットに関する情報を返します。
2. Redisクラスタモードの原理
2.1. クラスターの作成
Redis クラスターを作成する場合は、次の手順を実行します。
- ノードの開始: 事前に設定された各ノードで Redis サービスを開始します。Redis クラスター モードのノードの最小数は 3 で、これら 3 つはすべてマスター ノードです。これは、Redis クラスターの高可用性の最小要件を満たすためです。つまり、マスター ノードに障害が発生した場合、他のマスター ノードを介してフェイルオーバーが発生する可能性があります。ただし、この構成では、1 つのマスター ノードに障害が発生すると、過半数を達成するのに十分なマスター ノードがないため、クラスターはサービスを提供できなくなります。したがって、高可用性を確保するには、通常、3 つのマスター ノードと 3 つのスレーブ ノードを含む少なくとも 6 つのノードを持つことが推奨されます。
- クラスターの作成: ノード ハンドシェイクとも呼ばれ、Redis クラスター内のノード間の接続を確立し、Gossip プロトコルを通じて通信するプロセスを指します。
CLUSTER MEET
新しいノードがクラスターに参加する必要がある場合、クラスター内の任意のノードに、独自の IP アドレスとポート番号を含むコマンドが送信されます。コマンドを受信したノードはノード テーブルを更新し、ゴシップ プロトコルを通じて新しいノード情報をクラスター内の他のノードに伝播します。このようにして、ノードのハンドシェイクが完了し、新しいノードがクラスターに正常に参加します。
- スロットの割り当て: Redis クラスターでは、すべてのデータが 16384 スロットにマッピングされます。各ノードはスロットの一部を担当し、ノードにスロットが割り当てられた場合にのみ、それらのスロットに関連付けられたキーのコマンドを処理できます。クラスターを作成するとき、またはクラスター構造を調整するときに、
CLUSTER ADDSLOTS
このコマンドを使用してスロットをノードに割り当てることができます。 - マスター/スレーブ関係を設定する: クラスター内に複数のノードがある場合、データのバックアップと高可用性を実現するためにマスター/スレーブ関係を設定する必要があります。
2.2. 障害の発見
Redis クラスターでは、ノードはゴシップ プロトコルの一部であるピンポン メッセージを送信することによって相互に通信します。各ノードは他のノードに定期的に ping メッセージを送信します。cluster-node-timeout
ノードからの pong メッセージが時間内に受信されない場合、そのノードは障害が発生したとみなされ、主観的オフライン (pfail) 状態としてマークされます。
ノードが主観的にオフラインとしてマークされると、この情報はゴシップ プロトコルを通じてクラスター内に伝播されます。マスター ノードの半分以上がノードを主観的にオフラインとしてマークすると、そのノードは客観的にオフライン (失敗) としてマークされ、フェイルオーバー プロセスがトリガーされます。
2.3. フェイルオーバー
マスター ノードに障害が発生すると、クラスター内の他のマスター ノードがゴシップ プロトコルを通じて障害を感知します。これらのマスター ノードは、障害が発生したマスター ノードの代わりに、障害が発生したマスター ノードのスレーブ ノードの 1 つを選択します。このプロセスはフェイルオーバーと呼ばれます。
この方法は Redis センチネル モードのフェイルオーバーに似ていますが、センチネル モードではセンチネル ノードのみが障害検出とフェイルオーバーのプロセスに参加するのに対し、クラスター モードではすべてのマスター ノードがこのプロセスに参加します。これにより、フェイルオーバーの効率が向上し、障害回復の時間が短縮されます。
具体的なプロセスは次のとおりです。
-
適格性チェック: 障害が発生したマスター ノードのすべてのスレーブ ノードは、マスター ノードとの最後の通信時間をチェックして、障害が発生したマスター ノードを置き換える資格があるかどうかを判断します。
-
選出の準備時間: フェイルオーバーの対象となるスレーブ ノードは、失敗選出の時間を設定します。この時間に達した後でのみ、選出プロセスを開始できます。
-
選挙の開始: スレーブ ノードのスケジュールされたタスクが失敗選挙時間 (failover_auth_time) が到着したことを検出すると、選挙プロセスが開始されます。
-
選挙投票: スロットを保持しているマスター ノードは、失敗した選挙メッセージを処理して投票します。スロットを保持する各マスター ノードは、各構成エポックで 1 つのスレーブ ノードにのみ投票できるため、1 つのスレーブ ノードだけが投票の半分以上を取得できることが保証されます。
-
新しいマスター ノードを選出する: 投票の半分以上を獲得したスレーブ ノードが新しいマスター ノードとして選出されます。
-
クラスターに通知: 新しいマスター ノードは、クラスター内の他のノードにメッセージを送信し、新しいマスター ノードとして選択されたことを通知します。
-
スロット マッピングの更新: 新しいマスター ノードは、障害が発生したマスター ノードのすべてのスロットを引き継ぎ、クラスター内の他のノードは、新しいマスター ノードからメッセージを受信した後、独自のスロット マッピング情報を更新します。
-
サービスの提供を開始する: 新しいマスター ノードはサービスの提供を開始し、クライアントのリクエストを処理します。このプロセスにより、マスター ノードに障害が発生した場合にクラスターが迅速にフェイルオーバーできるようになり、クラスターの可用性が向上します。
Redis クラスターでは、フェイルオーバー プロセスにはマスター ノードの半分以上の投票が必要です。クラスター内に十分なマスター ノードがない場合、または複数のマスター ノードが同じマシンにデプロイされていて適切に動作できない場合、十分な投票を収集できず、フェイルオーバー プロセスは失敗します。
したがって、単一障害点を避けるために、Redis クラスターをデプロイするときに、すべてのマスター ノードが異なる物理マシンに分散されていることを確認する必要があります。これにより、特定の物理マシンに障害が発生した場合でも、マスター ノードの半分以上には影響が及ばず、クラスターの高可用性が確保されます。
2.4. クラスターの拡張
Redis クラスターの負荷が高すぎる場合やストレージ容量が不足している場合は、新しいノードを追加することで容量を拡張できます。新しいノードを追加した後、新しいノードがサービスの提供を開始できるように、いくつかのスロットを新しいノードに移行する必要があります。このプロセスはCLUSTER ADDSLOTS
コマンドを使用して実行できます。
拡張プロセス中、管理者または運用保守担当者は、Redis コマンド ライン ツール (redis-cli) またはその他の管理ツールを介してクラスターにコマンドを送信し、新しいノードの追加、スロットの割り当て、スロットの移行などの操作を実行する必要があります。
Redis クラスターの拡張プロセスには主に次の手順が含まれます。
- 新しいノードを追加する: まず、新しいサーバー上で Redis インスタンスを起動し、既存の Redis クラスターに追加する必要があります。これは
CLUSTER MEET
コマンドで実行できます。 - スロットの割り当て: 次に、スロットの一部を新しいノードに割り当てる必要があります。これは
CLUSTER ADDSLOTS
コマンドで実行できます。 - 移行スロット: 次に、一部のデータを古いノードから新しいノードに移行する必要があります。これは
CLUSTER MIGRATESLOT
コマンドで実行できます。このプロセス中、移行されたスロットは一時的に使用できなくなります。 - スロット マッピングの更新: 最後に、クラスター内のすべてのノードのスロット マッピング情報を更新して、新しいスロット割り当てを知らせる必要があります。これは
CLUSTER NODES
コマンドで実行できます。
以上がRedisクラスタの拡張プロセスです。スロットの移行プロセス中、移行されたスロットは一時的にサービスを提供できなくなるため、このプロセスはクラスター サービスに影響を与える可能性があることに注意してください。したがって、容量拡張操作を実行する場合は、サービスへの影響を軽減するために、負荷が低いときに実行するよう最善を尽くす必要があります。
2.5. クラスターの削減
Redis クラスターの負荷が低すぎる場合、またはアイドル状態のリソースが多すぎる場合は、一部のノードを削除することで容量を減らすことができます。ノードを削除する前に、このノード上のすべてのスロットを他のノードに移行してから、このノードを削除する必要があります。このプロセスはCLUSTER DELSLOTS
コマンドを使用して実行できます。
Redis クラスターの削減プロセスには主に次の手順が含まれます。
- データの移行: まず、スケールダウンする必要があるノード上のすべてのデータをクラスター内の他のノードに移行する必要があります。これは
CLUSTER MIGRATESLOT
コマンドで実行できます。このプロセス中、移行されたスロットは一時的に使用できなくなります。 - スロットの削除: 次に、スケールダウンする必要があるノード上のすべてのスロットを削除する必要があります。これは
CLUSTER DELSLOTS
コマンドで実行できます。 - ノードの削除: 最後に、スケールダウンする必要があるノードをクラスターから削除する必要があります。これは
CLUSTER FORGET
コマンドで実行できます。