記事ディレクトリ
1. Redis Cluster クラスターモードについての理解
1.1 Redis クラスターモードの概念
Redis Cluster は、データを複数のノードに分散して保存できる分散クラスター モードで、水平方向のスケーラビリティ、高可用性、およびより大きなストレージ容量を提供します。Redis クラスターには次の主要な機能があります。
-
分散データ ストレージ: Redis Cluster はデータを複数のスロットに分割し、異なるノードに分散します。各ノードは一部のスロット内のデータを管理する責任を負い、データを複数のノードに分散して、単一ノードのストレージ容量の制限を回避できます。
-
自動データシャーディング: Redis Cluster はハッシュ スロットを使用してデータをシャーディングし、クライアントはキーのハッシュ値に基づいてデータを正しいノードにルーティングします。これにより、データのシャーディングとルーティングが自動化され、データのシャーディングを手動で管理する必要がなくなります。
-
高可用性: Redis Cluster は、組み込みの高可用性メカニズムを提供します。データは複数のノード間で複製され、各スロットにはマスター ノードと複数のスレーブ ノードがあります。マスター ノードに障害が発生した場合、システムはデータの可用性を確保するために、新しいマスター ノードとしてスレーブ ノードを自動的に選択します。
1.2 Redis クラスターモードによって解決される問題
Redis クラスター モードは、大规模数据存储和高可用性
需要に応じて発生する問題を解決するために導入されました。Redis セントリー モードは前の記事で紹介しましたが、センチネル モードはシステムの高可用性を提供しますが、実際にはすべてのデータを単一のマスターとそれに対応するスレーブ ノードに保存する必要があります。このアーキテクチャは、大規模なデータ ストレージの課題に直面すると、主に次の課題と制限を含むいくつかの問題に遭遇します。
-
メモリの制限: Redis はインメモリ データベースであり、高速アクセスを提供するためにデータはメモリに保存されます。データ量が非常に大きく、単一のマスターおよびそれに対応するスレーブ ノードの物理メモリ容量に近づくか、それを超える場合、メモリ不足の問題が発生します。これにより、パフォーマンスが低下したり、システムがクラッシュしたりする可能性があります。
-
水平スケーリングの問題: Sentinel モードでは、ストレージ容量を拡張したり、より多くのリクエストを処理したりするには、通常、ハードウェアをアップグレードし、単一ノードのメモリ容量をより大規模に増やす必要があります。しかし、この垂直拡張方法には高コストと物理的制限の問題があり、大規模なデータストレージ要件には十分な柔軟性がありません。
これらの問題を解決するために、Redis はクラスター モードを導入しました。Redis 集群模式的核心思想是利用多组 Master/Slave 节点来分散存储数据,并提供更大的内存容量和高可用性
。Redis クラスター モードによって解決される問題と利点は次のとおりです。
問題 1: メモリの制限
Redis クラスター モードは、データを複数のノードに分散することでメモリの制約の問題を解決します。各マスター ノードはデータの一部を保存できるため、ノードが追加されるにつれてクラスター全体の合計メモリ容量が直線的に増加します。これにより、Redis Cluster は単一ノードのメモリをアップグレードすることなく、より大規模なデータを処理できるようになります。
問題2:水平展開問題
Redis クラスター モードは、シャーディング メカニズムを通じて水平方向の拡張を実現します。各シャードは、単一ノードの垂直方向の拡張に依存するのではなく、マスター/スレーブ ノードのセットによって管理されます。これにより、システムは、増大するストレージとリクエストの需要に対応するために、必要に応じてシャードを簡単に追加できます。この水平スケーリングのアプローチはより柔軟であり、さまざまなワークロードやデータ サイズに適応できます。
問題 3: 高可用性
Redis クラスター モードは、組み込みの高可用性サポートを提供します。各マスター ノードには、バックアップとして対応するスレーブ ノードがあります。マスター ノードに障害が発生した場合、対応するスレーブ ノードは新しいマスター ノードに自動的にアップグレードされ、データの可用性とシステムの継続的な動作が確保されます。この自動フェイルオーバー メカニズムにより、システムの安定性が大幅に向上します。
例:
たとえば、次の例では、データ セット全体が 1 TB であると想定されています。データを保存するために 3 セットのマスター/スレーブ ノードを導入することにより、各マシン セットはデータ セット全体の 1/3 を保存するだけで済みます。
具体的な例としては以下のようなものがあります。
上の写真では:
- Master1、Slave11、Slave12 には同じデータが保存されており、合計データの 1/3 を占めます。
- Master2、Slave21、Slave22には同じデータが保存されており、合計データの1/3を占めます。
- Master3、Slave31、Slave32 には同じデータが保存されており、合計データの 1/3 を占めます。
各スレーブは、対応するマスターのバックアップです。マスター ノードに障害が発生すると、データの可用性を維持するために、対応するスレーブ ノードが自動的に新しいマスターにアップグレードされます。
このように、Redis クラスター モードは、大規模なデータ ストレージと高可用性シナリオで直面するメモリ制限、水平拡張、高可用性の問題を解決し、Redis をより強力で信頼性の高いデータ ストレージ ソリューションにします。この分散アーキテクチャにより、Redis は大量のデータを処理し、ハードウェアのパフォーマンスや可用性の点で柔軟に拡張して、変化するビジネス ニーズに適応することができます。
2. データ断片化アルゴリズム
2.1 ハッシュ剰余アルゴリズム
ハッシュ剰余アルゴリズムは、データを異なるシャードに分散するために使用される、シンプルで一般的なデータ シャーディング アルゴリズムです。このアルゴリズムは分散システム、特にデータを複数のサーバーに保存して負荷のバランスを確保する必要がある場合によく使用されます。ハッシュ剰余アルゴリズムの基本原則と問題点は次のとおりです。
基本的:
N 個のシャードがあると仮定すると、各シャードには通常 0 から N -1 までの番号が割り当てられます。特定のデータ キーについて、次の手順に従って、データ キーをどのシャードに保存するかを決定します。
- データキーは、通常、ハッシュ関数 (MD5 や SHA-1 など) を使用してハッシュされ、ハッシュ値が取得されます。
- 結果として得られるハッシュ値の残りは N、つまりハッシュ値 %N です。結果は、データキーが属するシャード番号です。
例えば:
3 つのシャード (N=3) があり、データ キー「hello」を保存する必要があるとします。まず、「hello」に対してハッシュ演算を実行して (たとえば、MD5 アルゴリズムを使用して)、ハッシュ値「bc4b2a76b9719d91」を取得します。次に、このハッシュ値は 3 で変調され、結果は 0 になります。したがって、「hello」データ キーはシャード番号 0 に保存する必要があります。
問題点:
ハッシュ剰余アルゴリズムはシンプルで効果的なデータ シャーディング方法ですが、特にシャーディングを拡張または縮小する必要がある場合には、いくつかの問題もあります。
質問 1: 拡張の問題
新しいシャードを導入する必要があり、N が 3 から 4 に増加すると、元のマッピング ルールは破棄されます。したがって、各データキーのハッシュを再計算して、新しいシャード番号にマッピングする必要があります。これには大規模なデータ移行が必要となり、システムのパフォーマンスに悪影響を及ぼす可能性があります。
以下の例のように、Nが3の場合、21個のデータキーのハッシュ値分布を計算しました。ただし、新しいシャードが導入されると、3 つのデータ キーのハッシュ値のみが変更されず、他のデータ キーは新しいシャードに移行する必要があります。これにより、データ再配置のオーバーヘッドが発生します。
問題 2: データが不均一に分散している
もう 1 つの問題は、ハッシュ剰余アルゴリズムによりデータがシャード間で不均等に分散される可能性があることです。ハッシュの分布が不均一な場合、一部のシャードの負荷が高く、他のシャードの負荷が低く、パフォーマンスが不均一になる可能性があります。
要約すると、ハッシュ剰余アルゴリズムは単純なデータ シャーディング方法ですが、拡張が必要な場合やデータが不均等に分散されている場合に問題が発生する可能性があります。したがって、データシャーディングアルゴリズムを選択するときは、さまざまな要素を比較検討し、実際のニーズに基づいて最適な方法を選択する必要があります。コンシステント ハッシュやハッシュ スロット分割などの他のシャーディング アルゴリズムは、ハッシュ剰余アルゴリズムの問題の一部を解決できます。
2.2 一貫したハッシュアルゴリズム
コンシステント・ハッシュ・アルゴリズムは、データが動的に追加および削除される場合のデータ移行の問題を解決するアルゴリズムであり、分散システムで広く使用されています。基本的な考え方は、ハッシュ関数を使用してデータ キーとシャードをリング空間にマッピングすることであり、各シャードはリング上の特定の範囲内のデータを担当します。シャードを追加または削除する必要がある場合、すべてのデータではなく、データの一部のみを移行する必要があります。
基本的:
-
ハッシュ リングを作成する:まず、ハッシュ関数を使用して、考えられるすべてのデータ キーとシャードをリング空間 (通常は 0 から 2^32-1 の範囲のリング) にマッピングします。このリング上の各ポイントはハッシュ値に対応します。
-
シャードの割り当て:次に、各シャードをリング空間上の点にマッピングします。シャードの場所は、シャード識別子 (シャード名や ID など) をハッシュすることで特定できます。
-
データ マッピング:データを保存または検索する必要がある場合、同じハッシュ関数を使用してデータのキーを円形空間上の点にマッピングします。次に、リングの時計回り方向に沿ってデータ ポイントに最も近いシャードを見つけて、そのシャードにデータを保存します。
これは、リング全体を N 個の管轄区間に分割した N 個のシャードの位置に相当し、Key のハッシュ値が一定の区間に収まる場合には、その区間で管理されます。
アドバンテージ:
- 高いデータ移行効率:コンシステント ハッシュ アルゴリズムがシャードを拡張または縮小する場合、すべてのデータを再分散することなく、データの一部を移動するだけで済むため、データ移行のオーバーヘッドは比較的小さくなります。
- 負荷分散:データはリング空間に均等に分散されるため、各シャードの負荷は相対的にバランスが取れ、システムのパフォーマンスとスケーラビリティが向上します。
欠点:
- 不均等なデータ分散:コンシステント ハッシュ アルゴリズムはハッシュ関数を通じてデータを均等に分散しますが、実際のアプリケーションではデータ分散が不均一になる可能性があり、一部のシャードにはより多くのデータが保存され、他のシャードにはより少ないデータが保存され、データ スキューの問題が発生する可能性があります。
拡張例:
コンシステント ハッシュ アルゴリズムでは、シャーディングの拡張操作は比較的効率的です。新しいシャードが導入される場合、元のシャードの位置に影響を与えることなく、新しい点を環状空間に追加するだけで済みます。データ移行には、新しいシャードの場所にマッピングする必要があるデータのみが含まれます。
上記の例では、元々シャード 0 にマッピングされていたデータの一部のみが新しいシャード 3 に移行され、他のシャードのデータは影響を受けません。これにより、データ移行の規模が軽減され、拡張作業の効率が向上します。
要約すると、コンシステント ハッシュ アルゴリズムは、データの動的なシャーディング管理を効果的に解決するアルゴリズムであり、データ移行のコストを削減し、負荷分散をサポートしますが、不均一なデータ分散が引き起こす可能性がある問題に注意する必要があります。データのスキューに影響します。
2.3 ハッシュスロット分割アルゴリズム
データが動的に追加および削除されるときの高いデータ移行コストと不均一なデータ分散の問題を解決するために、Redis Cluster はハッシュ スロット パーティショニング アルゴリズムを導入します。このアルゴリズムの中心となるアイデアは、ハッシュ関数を使用して、キーとデータのシャードを円形空間内の異なるスロット (ハッシュ スロット) にマッピングすることです。各シャードは、特定のデータ キーではなくスロットの一部を管理します。
基本的:
- ハッシュ関数はハッシュ スロットを計算します:データ キーごとに、ハッシュ関数 (crc16 など) を使用してそのハッシュ値を計算し、16384 を法とするハッシュ値を取得します。結果はデータ キーのハッシュです。スロット番号。
hash_slot = crc16(key) % 16384
- ここでの 16384 はスロットの総数で、16 * 1024、つまり 2 14です。
-
ハッシュ スロットをシャードに割り当てる: Redis Cluster はこれらのハッシュ スロットを各シャードに均等に割り当て、各シャードがスロットの一部の管理を担当するようにします。シャード化された各ノードは、保持するスロットの範囲を記録します。
たとえば、3 つのシャードが次のように割り当てられる場合があります。
- シャード 0 はスロット範囲 [0, 5461] を担当します。
- シャード 1 はスロット範囲 [5462、10923] を担当します。
- シャード 2 はスロット範囲 [10924、16383] を担当します。
ここでの割り当ては柔軟であり、スロット範囲は連続している必要はありません。
-
ハッシュ スロットへのデータ マッピング:データを保存または検索する必要がある場合、同じハッシュ関数を使用してデータのキーをハッシュ スロット番号にマッピングします。次に、ハッシュ スロット番号に基づいてそのスロットを担当するシャードを見つけ、そのシャードにデータを保存します。
-
拡大
新しいシャード No. 3 を追加するなど、拡張が必要な場合は、元のスロットに従って再割り当てできます。可能なスケーリングの例を次に示します。
初期割り当て:
- シャード No. 0: [0, 4095]、合計 4096 スロット
- シャード No. 1: [5462, 9557]、合計 4096 スロット
- シャード No. 2: [10924, 15019]、合計 4096 スロット
拡張後の配布:
- シャード No. 0: [0, 3412]、合計 3413 スロット
- シャード No. 1: [5462, 6874]、合計 1413 スロット
- シャード No. 2: [10924, 12336]、合計 1413 スロット
- シャード No. 3: [3413, 4095] + [6875, 9557] + [12337, 15019]、合計 3414 スロット
この例では、新しいシャードに対応するために既存のスロットを再割り当てする方法を示します。新しいシャード No. 3 はいくつかのスロットを取得し、スロットの均等な配分を維持するために元のスロットも他のシャードに再割り当てされました。この方法により、容量拡張時のデータ移行規模が軽減され、拡張作業の効率が向上します。
実際に Redis クラスターのシャーディングを使用する場合、特定のシャードに割り当てられるスロットを手動で指定する必要がないことにも注意してください。特定のシャードが保持すべきスロットの数を指定するだけで、Redis が後続のスロット割り当てと関連するデータ移行作業を自動的に処理します。この自動化されたスロット管理方法により、クラスターの構成とメンテナンスの複雑さが大幅に簡素化され、クラスターの拡張と管理が容易になります。
アドバンテージ:
-
効率的なデータ移行:ハッシュ スロット パーティショニング アルゴリズムは、大規模なデータ移行を必要とせず、シャードの拡張または縮小時にスロットを再割り当てするだけで済むため、データ移行のコストとシステム パフォーマンスへの影響が削減されます。
-
負荷分散:ハッシュ スロット パーティショニング アルゴリズムは、異なるシャードにスロットを均等に分散することでデータ負荷分散を実現し、システムのパフォーマンスとスケーラビリティを向上させます。
欠点:
-
シャードの数は多すぎないでください。シャードが多すぎると、ネットワーク ハートビート パケット通信のオーバーヘッドが増加し、スロット構成のビットマップ サイズも大きくなる可能性があるため、通常、Redis クラスターのシャード数が 1,000 を超えることはお勧めできません。大きめです。
-
データの均等な分散が必ずしも保証されているわけではありません。アルゴリズムはスロットを均等に分散しようとしますが、実際にはデータの分散は必ずしも均一ではないため、一部のシャードにはより多くのデータが保存される一方、他のシャードにはより少ないデータが保存され、データ スキューが発生する可能性があります。質問。
ここでさらに 2 つの質問があります。
質問 1: Redis クラスターには最大 16384 個のシャードがありますか?
Redis クラスターはスロット数を 16384 に制限しません。この数は単なるデフォルト値です。実際、Redis Cluster はスロット数のカスタマイズをサポートしていますが、パフォーマンスとメモリ オーバーヘッドのバランスをとるために適切なスロット数の選択に注意する必要があります。
質問 2: デフォルトのスロット数が 16384 であるのはなぜですか?
スロット数を 16384 としたのは、メモリのオーバーヘッドと通信効率を考慮したためです。スロットの数が多いと、各ノードが保持するスロット情報をハートビート パケットに含める必要があるため、ノード間のハートビート パケットの通信オーバーヘッドが増加します。同時に、スロットの数が増えるとビットマップが大きくなり、より多くのメモリを占有するようになります。したがって、16384 は適度な値とみなされ、ほとんどのシナリオに適しています。
3. Docker シミュレーションに基づいて Redis クラスターを構築する
分散システムでは、Redis クラスターはデータの可用性とパフォーマンスを向上させるために使用される一般的なアーキテクチャです。Redis クラスターは、複数のノードにデータを分散することで高可用性と負荷分散を実現します。以下では、Docker を使用して Redis クラスターのローカル構築をシミュレートする方法を紹介し、クラスター トポロジ、構成ファイルの生成、コンテナー オーケストレーション、起動、クラスターの作成、その他の手順について説明します。
3.1 対象クラスタのトポロジ
以下は、Docker シミュレーションを通じて Redis クラスターを構築する場合のターゲット トポロジです。
トポロジ図:
例証します:
- このクラスターには、シャード 0、シャード 1、シャード 3 という 3 つのシャードがあります。
- 各シャードは Redis のマスター/スレーブ構造であり、各マスター/スレーブ構造には 1 つのマスター ノードと 2 つのスレーブ ノードが含まれます。
- コンテナの作成時に各コンテナに静的 IP が割り当てられ、その範囲は 172.30.0.101 ~ 172.30.0.111 です。
- 最初の 9 つのノードはクラスターの確立に使用され、次の 2 つのコンテナーはクラスターの拡張を示すために使用されます。
3.2 ディレクトリと設定ファイルの作成
Redis クラスターをセットアップするには、redis-cluster
という名前のディレクトリを作成し、その中に と という 2 つの重要なファイルを作成するdocker-compose.yml
必要がありますgenerate.sh
。
redis-cluster/
├── docker-compose.yml
└── generate.sh
このうち、docker-compose.yml
ファイルは Redis コンテナを配置および管理するために使用され、generate.sh
ファイルは Redis 構成ファイルをバッチで生成するために使用されるシェル スクリプトですredis.conf
。
generate.sh
ファイルの内容は次のとおりです。
for port in $(seq 1 9); \
do \
mkdir -p redis${port}/
touch redis${port}/redis.conf
cat << EOF > redis${port}/redis.conf
port 6379
bind 0.0.0.0
protected-mode no
appendonly yes
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 172.30.0.10${port}
cluster-announce-port 6379
cluster-announce-bus-port 16379
EOF
done
# 注意 cluster-announce-ip 的值有变化.
for port in $(seq 10 11); \
do \
mkdir -p redis${port}/
touch redis${port}/redis.conf
cat << EOF > redis${port}/redis.conf
port 6379
bind 0.0.0.0
protected-mode no
appendonly yes
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 172.30.0.1${port}
cluster-announce-port 6379
cluster-announce-bus-port 16379
EOF
done
例証します:
redis.conf
このスクリプトは、クラスターの基本構成と構成パラメーターを含むRedis 構成ファイルをバッチで作成するために使用されます。- 最初のループでは、最初の 9 ノードの構成が生成されます。IP
cluster-announce-ip
アドレスの一意性を確保するために、 の値はノードごとに異なることに注意してください。 - 2 番目のループは、クラスターの拡張を示すために使用される次の 2 つのノードの構成を生成します。また、 の
cluster-announce-ip
値が一意であることを確認する必要があります。 - スクリプトを実行すると、
redis-cluster
ディレクトリ内に複数のサブディレクトリが作成され、各サブディレクトリはノードに対応し、対応する構成ファイルが含まれます。
注文の実行:
bash generate.sh
結果:
redis-cluster/
├── docker-compose.yml
├── generate.sh
├── redis1
│ └── redis.conf
├── redis10
│ └── redis.conf
├── redis11
│ └── redis.conf
├── redis2
│ └── redis.conf
├── redis3
│ └── redis.conf
├── redis4
│ └── redis.conf
├── redis5
│ └── redis.conf
├── redis6
│ └── redis.conf
├── redis7
│ └── redis.conf
├── redis8
│ └── redis.conf
└── redis9
└── redis.conf
Redis 構成ファイルを生成するスクリプトが正常に実行されていることがわかります。
生成された構成ファイルの内容を表示します。
generate.sh
スクリプトでは、redis.conf
ループを通じて Redis コンテナーごとに個別の構成ファイルが生成されます。以下は、redis1
コンテナーの構成ファイルの例です。他のコンテナーの構成ファイルも似ていますが、唯一の違いはcluster-announce-ip
パラメーターです。
port 6379
bind 0.0.0.0
protected-mode no
appendonly yes
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 172.30.0.101
cluster-announce-port 6379
cluster-announce-bus-port 16379
例証します:
port 6379
: Redis サーバーがリッスンするポート番号を指定します。bind 0.0.0.0
: Redis サーバーへのリモート接続を許可します。protected-mode no
: 保護モードを無効にして、クラスター ノード間の通信を許可します。appendonly yes
: データの永続性のために永続性ログを有効にします。cluster-enabled yes
: Redis クラスターのサポートを有効にします。cluster-config-file nodes.conf
: クラスタ構成ファイルの名前を指定します。cluster-node-timeout 5000
: ノードのタイムアウトをミリ秒単位で設定します。cluster-announce-ip
: このパラメータは、クラスタ内で通信するノードの IP アドレスを構成し、各ノードがノードの識別と接続のために一意の IP アドレスを持つようにします。cluster-announce-port
: ノードが自身をアナウンスするために使用するポート番号を構成します。cluster-announce-bus-port
: ノードがクラスタバス通信に使用するポート番号を設定します。
これらの構成ファイルを生成すると、Redis クラスター内の各ノードが適切な構成になり、ノードが連携して完全なクラスターを構築できるようになります。各ノードのcluster-announce-ip
パラメータの違いにより、各ノードがクラスタが適切に機能するために必要な一意の ID を持つことが保証されます。
3.3 docker-compose.yml ファイルを作成する
docker-compose.yml
ファイルは、Docker コンテナーの定義と構成に使用されるオーケストレーション ファイルです。これにより、単一のファイルで複数のコンテナーを定義したり、これらのコンテナー間の関係や構成パラメーターを定義したりできます。
内容は大きく分けて以下の2部に分かれます。
- まずネットワーク LAN を作成し、ネットワーク セグメントを 172.30.0.0/24 として割り当てます。
- 次に、構成ファイルのマッピング、ポートのマッピング、コンテナーの IP アドレスに注意して各ノードを構成します。
例証します:
- その後の観察や操作を容易にするため、固定IPに設定します。
- ここでのポート マッピングを設定する必要はありません。設定の目的は、 を介した
宿主机 IP: 映射的端口
アクセスを有効にすることです。構成されていない場合は、IP: 6379
コンテナ自体を介してアクセスすることもできます。
docker-compose.yml
ファイルの内容は次のとおりです。
version: '3.7'
services:
redis1:
image: 'redis:5.0.9'
container_name: redis1
restart: always
volumes:
- ./redis1/:/etc/redis/
ports:
- 6371:6379
- 16371:16379
command: redis-server /etc/redis/redis.conf
networks:
mynet:
ipv4_address: 172.30.0.101
redis2:
image: 'redis:5.0.9'
container_name: redis2
restart: always
volumes:
- ./redis2/:/etc/redis/
ports:
- 6372:6379
- 16372:16379
command: redis-server /etc/redis/redis.conf
networks:
mynet:
ipv4_address: 172.30.0.102
redis3:
image: 'redis:5.0.9'
container_name: redis3
restart: always
volumes:
- ./redis3/:/etc/redis/
ports:
- 6373:6379
- 16373:16379
command: redis-server /etc/redis/redis.conf
networks:
mynet:
ipv4_address: 172.30.0.103
redis4:
image: 'redis:5.0.9'
container_name: redis4
restart: always
volumes:
- ./redis4/:/etc/redis/
ports:
- 6374:6379
- 16374:16379
command: redis-server /etc/redis/redis.conf
networks:
mynet:
ipv4_address: 172.30.0.104
redis5:
image: 'redis:5.0.9'
container_name: redis5
restart: always
volumes:
- ./redis5/:/etc/redis/
ports:
- 6375:6379
- 16375:16379
command: redis-server /etc/redis/redis.conf
networks:
mynet:
ipv4_address: 172.30.0.105
redis6:
image: 'redis:5.0.9'
container_name: redis6
restart: always
volumes:
- ./redis6/:/etc/redis/
ports:
- 6376:6379
- 16376:16379
command: redis-server /etc/redis/redis.conf
networks:
mynet:
ipv4_address: 172.30.0.106
redis7:
image: 'redis:5.0.9'
container_name: redis7
restart: always
volumes:
- ./redis7/:/etc/redis/
ports:
- 6377:6379
- 16377:16379
command: redis-server /etc/redis/redis.conf
networks:
mynet:
ipv4_address: 172.30.0.107
redis8:
image: 'redis:5.0.9'
container_name: redis8
restart: always
volumes:
- ./redis8/:/etc/redis/
ports:
- 6378:6379
- 16378:16379
command: redis-server /etc/redis/redis.conf
networks:
mynet:
ipv4_address: 172.30.0.108
redis9:
image: 'redis:5.0.9'
container_name: redis9
restart: always
volumes:
- ./redis9/:/etc/redis/
ports:
- 6379:6379
- 16379:16379
command: redis-server /etc/redis/redis.conf
networks:
mynet:
ipv4_address: 172.30.0.109
redis10:
image: 'redis:5.0.9'
container_name: redis10
restart: always
volumes:
- ./redis10/:/etc/redis/
ports:
- 6380:6379
- 16380:16379
command: redis-server /etc/redis/redis.conf
networks:
mynet:
ipv4_address: 172.30.0.110
redis11:
image: 'redis:5.0.9'
container_name: redis11
restart: always
volumes:
- ./redis11/:/etc/redis/
ports:
- 6381:6379
- 16381:16379
command: redis-server /etc/redis/redis.conf
networks:
mynet:
ipv4_address: 172.30.0.111
networks:
mynet:
ipam:
config:
- subnet: 172.30.0.0/24
ファイルの内容の説明:
docker-compose.yml
このファイルは、Docker コンテナーのオーケストレーションを定義および構成するために Docker Compose ツールによって使用される構成ファイルです。提供したファイルでは、主に Redis クラスター内の 11 ノードのコンテナーを構成するために使用されます。ファイルの内容の詳細な説明は次のとおりです。
-
version: '3.7'
: Docker Compose ファイルのバージョンを指定します。 -
services
: 起動する各サービス(コンテナ)とその構成を定義します。 -
各 Redis ノードの構成ブロックは次の例のようになります。
redis1
: コンテナの名前を定義します。image: 'redis:5.0.9'
: 使用する Redis イメージとそのバージョンを指定します。container_name: redis1
: コンテナの名前を指定します。restart: always
: コンテナを終了後に常に自動的に再起動するように設定します。volumes
: ホスト上の構成ファイルをコンテナ内のディレクトリにマウントするように指定します。ports
: コンテナ内のポートをホストにマップし、ホストの IP アドレスとマップされたポートを介したアクセスを許可します。command: redis-server /etc/redis/redis.conf
: コンテナ起動時に実行するコマンドを指定します ここではRedisサービスを起動します。networks
: コンテナが属するネットワークを指定します。mynet
: カスタム ネットワーク名が定義されています。
-
networks
: カスタム ネットワークが定義されmynet
、IP アドレス管理 (IPAM) 構成が構成されています。コンテナーが属する IP サブネット範囲を指定し172.30.0.0/24
、各コンテナーに一意の IPv4 アドレスを割り当てます。
全体として、このdocker-compose.yml
ファイルはカスタム ネットワークを構成しmynet
、Redis ノードの 11 個のコンテナを開始します。各コンテナは異なる IPv4 アドレスを持ち、異なる構成ファイルをマウントし、ホストの IP アドレスとポートを介してアクセスできるようにポートをマップします。これらのコンテナにアクセスします。これらのコンテナは連携して Redis クラスターを構築できます。
3.4 コンテナの起動
次のコマンドを使用して、オーケストレーションしたすべてのコンテナを起動します。
docker-compose up -d
起動結果:
docker ps -a
このコマンドを使用すると、現在のコンテナをすべて表示できます。
この時点で、11 個の Redis ノードが正常に作成され、実行されています。
3.5 クラスターの作成
Redis クラスターを作成するときは、最初の 9 つの Redis ノードを使用してクラスターを構築します。
クラスターを作成するコマンドは次のとおりです。
redis-cli --cluster create 172.30.0.101:6379 172.30.0.102:6379 172.30.0.103:6379 172.30.0.104:6379 172.30.0.105:6379 172.30.0.106:6379 172.30.0.107:6379 172.30.0.108:6379 172.30.0.109:6379 --cluster-replicas 2
コマンドの詳細な説明:
-
redis-cli
: これは、Redis サーバーと対話し、さまざまな Redis コマンドを実行するために使用される Redis コマンド ライン ツールです。 -
--cluster create
: この部分は、redis-cli
コマンドに Redis クラスターを作成するように指示します。 -
172.30.0.101:6379
To172.30.0.109:6379
: これは、クラスター内の各 Redis ノードの IP アドレスとポート番号です。ここにリストされているのは、Redis クラスターの一部を形成する 9 つのマスター ノードです。 -
--cluster-replicas 2
: このオプションは、各マスター ノードがデータをバックアップするために必要なスレーブ ノードの数を指定します。このコマンドでは、2 に設定されています。これは、各マスター ノードがデータをバックアップするために 2 つのスレーブ ノードを持つことを意味します。
このコマンドを実行すると、Redis は指定された IP アドレスとポート番号に基づいて Redis クラスターを作成し、各マスター ノードが 2 つのスレーブ ノードを持つように構成します。このようなクラスター構成は、ノードに障害が発生した場合でもデータを確実に利用できるように、高可用性と耐障害性を提供するように設計されています。これは、マスター ノードの複数のスレーブ ノードにデータを複製することによって実現されます。
結果:
コマンド送信後、最初に以下のインタラクティブ情報が表示されます: 上記のインタラクティブ情報は、
Redis クラスターの作成時に表示されますが、主にクラスター構成が期待どおりであるかどうかを確認し、誤操作を防ぐために使用されます。この情報の詳細な説明は次のとおりです。
-
まず、Redis クラスター作成コマンドはハッシュ スロットの割り当てを実行します。ハッシュ スロットは、Redis クラスターがデータをシャーディングするために使用する方法であり、各マスター ノードは特定の範囲のハッシュ スロットを担当します。
-
次に、このコマンドは、マスター ノードの ID、IP アドレス、ポート、マスター ノードに割り当てられたハッシュ スロットの範囲など、各マスター ノードに関する情報を一覧表示します。
-
次に、このコマンドは、スレーブ ノードの IP アドレスとポート、複製先のマスター ノードの ID など、各スレーブ ノードに関する情報を一覧表示します。
-
最後に、コマンドは構成を受け入れるかどうかを尋ねます。「上記の構成を設定できますか? (受け入れるには「yes」と入力します):」というプロンプトが表示され、確認を待ちます。
- 同意してクラスターの作成を続行する場合は、「yes」と入力して Enter キーを押します。
- 構成に満足できない場合、または変更する必要がある場合は、「no」と入力して Enter キーを押すと、コマンドを再実行して構成を変更できます。
この対話型の確認プロセスは、Redis クラスターの作成時に構成を注意深くチェックして確認し、エラーや予想どおりでないクラスター構成を回避できるようにするためのものです。構成が正しいことが確認されると、Redis は実際の要件に従ってクラスターの作成を続行します。
「はい」を入力した後:
これは、Redis クラスターが正常に作成された後の出力情報です。出力情報の説明は次のとおりです。
-
「ノード構成が更新されました」: ノード構成が更新され、新しいクラスター構成が有効になったことを示します。
-
「各ノードに異なる構成エポックを割り当てる」: 各ノードには、異なる構成エポック (構成エポック) が割り当てられます。構成エポックは、ノード構成の変更を管理するために使用される内部カウンターです。
-
「クラスターに参加するための CLUSTER MEET メッセージの送信」: クラスターに参加できるように、CLUSTER MEET メッセージが各ノードに送信されていることを示します。
-
「クラスターの参加を待っています...」: クラスター内の各ノードが参加するのを待っています。これは待機プロセスです。
-
「クラスタチェックの実行中(ノード172.30.0.101:6379を使用)」: クラスタチェックが実行されており、ノード(172.30.0.101:6379)が参照ノードとして使用されます。
-
次に、各ノードの情報です。これには、ノードのタイプ (マスター ノードまたはスレーブ ノード)、ノードの ID、IP アドレス、ポート、およびノードが担当するハッシュ スロット範囲とレプリケーション関係が含まれます。
-
「[OK] すべてのノードがスロット構成に同意します。」: すべてのノードがハッシュ スロット構成に同意し、クラスター内の各ノードにハッシュ スロットが正しく割り当てられていることを示します。
-
「開いているスロットを確認...」および「スロット カバレッジを確認...」: 未割り当てのハッシュ スロットがあるかどうか、およびハッシュ スロットが完全に割り当てられているかどうかを確認していることを示します。「[OK] すべての 16384 スロットがカバーされました。」は、16384 個のハッシュ スロットすべてが割り当てられ、カバーされたことを意味します。これは成功の兆候です。
この情報は、Redis クラスターが正常に作成され、すべてのノードがクラスターに参加し、ハッシュ スロットが正しく構成されていることを示します。これで、Redis クラスターの使用を開始できます。
3.5 デモクラスターの使用法
現時点では、Redis クライアントを使用してクラスター内の任意のノードに接続することは、クラスター全体に接続することと同等です。
予防:
- クライアントは
-c
オプションを追加する必要があります。追加しないと、キーが現在のノードのシャード領域に収まらない場合、操作は不可能になります。-c
このオプションは、リクエストを対応するノードに自動的にリダイレクトします。
クラスターに接続します。
ここでは接続された172.30.0.101: 6379
Redis ノードを例として、接続コマンドを以下に示します。
redis-cli -h 172.30.0.101 -p 6379 -c
クラスター全体の情報を表示します。
cluster nodes
コマンドを使用してクラスター全体を表示します。
この例では、Redis クラスター内のノード (172.30.0.101:6379) に接続し、-c
リクエストが正しいノードに自動的にリダイレクトされるようにするオプションを使用しました。次に、CLUSTER nodes
コマンドを実行してクラスター全体のノード情報を表示しました。
出力情報の簡単な説明は次のとおりです。
- 各行はクラスター内のノードを表します。
- 各ノードには一意の識別子があります。
- ノードの IP アドレスとポート番号がリストされます。
- ノードの役割 (マスターまたはスレーブ) も指定されます。
- マスター ノードの場合は、管理するスロットの範囲もリストされます。
- スレーブの場合は、複製元のマスターを指定します。
この例では、クラスター内のさまざまなノードと、それらの間の関係 (マスター/スレーブ関係やスロット割り当てなど) を確認できます。これにより、Redis クラスター全体のトポロジーとステータスを理解できるようになります。
現在クラスターに接続しているクライアントでキーを設定または取得する場合、設定または取得するキーが現在のノードのシャードにない場合は、対応するノードにリダイレクトされます。
4. クラスター障害の処理
4.1 マスターノードのダウン
この時点で、マスター ノードを手動で停止して、マスター ノードのダウンタイムをシミュレートできます。たとえば、上記のトポロジでは、 、 、 がマスターノードredis1
であることがわかり、停止するノードを選択できます。redis2
redis3
たとえば、redis1
ノードを停止するには:
docker stop redis1
結果:
正常に停止したことが分かりましたredis1
。
4.2 Redisクラスタ障害時の自動転送とその原理
自動フェイルオーバーを観察します。
この時点で、redis2
ノードに接続し、クラスター内のすべてのノード情報を再度表示します。
上記の情報によれば、次のことがわかります。
- この時点で、クラスター内の
172.30.0.101:6379
ノードのステータスは次redis1
のとおりですfail
。 - そして
172.30.0.105:6379
、そのノードは、シャード内の新しいマスター ノードredis5
になります。0 - 5460
- 別のスレーブ ノード
172.30.0.106:6379
、つまり のスレーブ ノードにredis6
もなりました。redis5
フェイルオーバーの原則:
Redis クラスターのフェイルオーバーとは、Redis クラスター内のマスター ノードに障害が発生した場合に、システムがバックアップ スレーブ ノードを新しいマスター ノードに自動的にアップグレードして、データの可用性と高可用性を維持できることを意味します。フェイルオーバーは Redis クラスターの重要な機能の 1 つであり、ノードに障害が発生した場合でもシステムの継続的な安定した動作を保証します。
Redis クラスターのフェイルオーバーがどのように機能するかは次のとおりです。
-
マスター ノードの障害検出: Redis クラスター内の他のノードは、マスター ノードの正常性状態を定期的に検出します。マスター ノードが利用できなくなると (クラッシュするか到達不能になるなど)、他のノードはこれに気づきます。
-
新しいマスター ノードを選択する: クラスター内のノードがマスター ノードが使用できないことを検出すると、新しいマスター ノードを選択するための投票が開始されます。投票は通常、ノードのレプリケーション オフセット、つまりどのノードが最新のデータを持っているかに基づいて行われます。
-
選出プロセス: クラスター内の各ノードは選出を開始でき、新しいマスター ノードを選択するためのコンセンサスに達しようとします。通常、最新のデータを持つスレーブ ノードが新しいマスター ノードとして選択されます。他のノードは新しいマスター ノードのスレーブ ノードになります。
-
データの同期: 新しいマスター ノードが選択されると、他のノードは新しいマスター ノードからのデータの同期を開始します。これにより、新しいマスターに以前のマスターと同じデータが確実に含まれます。
-
クライアントのリダイレクト: フェイルオーバーが完了すると、Redis Cluster はクライアントと他のノードに新しいマスター ノードの場所を通知し、クライアントが接続を更新できるようにします。
つまり、Redis クラスターのフェイルオーバーは自動分散プロセスであり、マスター ノードに障害が発生した場合のデータの可用性とシステムの回復可能性が保証されます。これにより、Redis Cluster は、可用性とスケーラブルなアプリケーションを構築するための強力なツールになります。
4.3 ダウンしたマスターノードの復旧
先ほど停止したノードの復元を試みますredis1
。起動コマンドは次のとおりです。
docker start redis1
起動結果:
ノードが正常に起動されたことがわかりましたredis1
。
Redis クラスターに接続し、クラスター内のノード情報を表示します。
redis1
復旧後、ノードがredis5
スレーブノードになっていることがわかりました。
5. クラスターの拡大
容量拡張は開発中に遭遇する一般的なシナリオであり、ビジネスが発展するにつれて、既存のクラスターでは増大するデータに対応できなくなる可能性があります。現時点では、クラスターに新しいマシンを追加すると、記憶域が大きくなる可能性があります。
したがって、分散の本質は、より多くのマシンを使用し、より多くのハードウェア リソースを導入することであることがわかります。
5.1 クラスターに新しいノードを追加する
redis1 - redis9
のノードはの上のクラスタに形成されています。次に、redis10
と がredis11
このクラスタに追加されます。redis10
ここでは、このノードのマスターノードとredis11
スレーブノードとみなされます。
redis10
ノードをクラスターに追加します。
redis-cli --cluster add-node 172.30.0.110:6379 172.30.0.101:6379
例証します:
add-node
その後の最初のアドレス セットは新しいノードのアドレスで、2 番目のアドレス セットはクラスター内の任意のノードのアドレスで、どのノードであるかを示します。- 上記のコマンドを使用して追加されたノードは、クラスター内のマスター ノードになります。
クラスター内の任意のノードに接続し、クラスターのステータスを確認します。クラスターに正常に参加してマスター ノードになったが、スロットが割り当てられていないことが
わかります。redis10
5.2 スロットの再割り当て
次のコマンドを使用してスロットを再割り当てします。
redis-cli --cluster reshard 172.30.0.101:6379
例証します:
reshard
後のアドレスはクラスター内の任意のノードのアドレスであり、スロットが再割り当てされるクラスターを示すことを意味します。- 単語のスペルに注意してください。これは
reshard
(re-share) ではなく (re-segmentreshared
) であり、複数の を書かないように注意してくださいe
。
上記のコマンドを実行すると対話型操作に入り、Redis はユーザーに次の内容の入力を求めます。
- 再シャーディングする必要があるスロットの数は? 均等に分配するには、ここに 4096 と入力します。
- どのノードがこれらの再割り当てされたスロットを受け取るか。ここに
172.30.0.110:6379
、redis10
クラスター内のこのノードの ID を入力します。 - これらの再割り当てされたスロットはどのノードから転送されますか? ここに入力すると、
all
他のすべてのノードが移動されることを意味します。
実行の流れは、
全ての移動作業の準備が完了すると、再度結果を導入するかどうかの質問が表示され、「はい」を入力した場合のみ、実際のスロット移動が実行されます。
最後に、クラスターに再度接続して、クラスターのノード情報を表示できます。
redis10
割り当てられたスロット範囲は 0 ~ 1364、5461 ~ 6826、10923 ~ 12287 であり、他のマスター ノードのスロットもそれに応じて削減されていることがわかります。
5.3 新しいマスターノードにスレーブノードを追加する
現在新たに追加されたノードは 1 つのマスター ノードのみであり、この時点で拡張目標は当初達成されています。ただし、クラスターの可用性を確保するには、新しいマスター ノードにスレーブ ノードを追加して、
マスター ノードがダウンした後にそれを置き換えるスレーブ ノードが確実に存在するようにする必要があります。
スレーブ ノードを追加するコマンドは次のとおりです。
redis-cli --cluster add-node 172.30.0.111:6379 172.30.0.101:6379 --cluster-slave
例証します:
add-node
後ろの最初のアドレスのセットは追加されるスレーブ ノードのアドレスであり、2 番目のアドレスのセットは追加されるスレーブ ノードのマスター ノードのアドレスです。--cluster-slave
追加するノードがスレーブノードであることを示します。
実行プロセス:
最後に、クラスターに再度接続し、クラスターのノード情報を表示できます。ノードの ID に従って、スレーブ ノードが正常に追加され
たことがわかります。redis10
redis11
6. クラスターの削減
Redis クラスターでは、拡張は比較的一般的な操作ですが、縮小は実際には非常にまれな操作です。ここでは、縮小の手順を簡単に理解できます。
次に、新しく追加した2 つのノードredis10
とノードを削除する方法を説明します。redis11
6.1 スレーブノードの削除
redis10
まず、スレーブ ノードを削除する必要がありますredis11
。削除コマンドは次のとおりです。
# redis-cli --cluster del-node [集群中任⼀节点ip:port] [要删除的从机节点 nodeId]
redis-cli --cluster del-node 172.30.0.101:6379 d35c427842bd1ab776ddbbda031f410a5d8ddb99
例証します:
del-node
オプションはノードが削除されることを示しますdel-node
次のアドレスはクラスター内の任意のノードのアドレスで、ノードが削除されるクラスターを示します。- 次に削除するノードのIDです。
削除プロセス:
クラスターに接続して、クラスターのノード情報を表示できます。
正常に削除されたことがわかりますredis11
。
6.2 スロットの再割り当て
スロットを再割り当てするコマンドは上記と同じです。
redis-cli --cluster reshard 172.30.0.101:6379
実行後も対話型操作を開始します。
なお、今回削除するマスターノードには4096スロットが含まれており、redis10
このノードの4096スロットを1365+1365+1366の3つに分割し、それぞれ他の3つのマスターノードに割り当てます。これにより、reshard
将来的にはクラスターの各シャードのスロット数を均等に分散できるようになります。
最初の再割り当て: redis5
1365 スロットに割り当て
- スロットを受け取るノード ID が
redis5
ノード ID であり、Source ノードにはredis10
ノード ID が入ります。
redis2
2 回目の再割り当て: 1365 スロットに割り当て
- スロットを受け取るノード ID が
redis2
ノード ID であり、Source ノードにはredis10
ノード ID が入ります。
redis3
3 回目の再割り当て: 1366 スロットに割り当て
- スロットを受け取るノード ID が
redis3
ノード ID であり、Source ノードにはredis10
ノード ID が入ります。
クラスターに接続し、クラスターのノード情報を表示します。
redis10
ノードにはこれ以上スロットがないことがわかりました。
6.3 マスターノードの削除
最後に、redis10
クラスターからノードを削除します。
# redis-cli --cluster del-node [集群中任⼀节点ip:port] [要删除的从机节点 nodeId]
redis-cli --cluster del-node 172.30.0.101:6379 9b12a2493edecd6cfa70d811d9383c0c5130dcf6
実装プロセス:
redis10
クラスター情報を再度確認すると、ノードがクラスター内になくなっていることがわかります。
7. まとめ
この記事では、次の主な内容を含む、Redis Cluster クラスター モードについて詳しく説明します。
-
Redis Cluster クラスター モードの概念: まず、Redis Cluster クラスター モードの基本概念を紹介し、それがどのようにデータを複数のノードに分散し、高可用性と水平スケーラビリティを提供するかを理解します。
-
データ シャーディング アルゴリズム: ハッシュ剰余アルゴリズム、一貫性のあるハッシュ アルゴリズム、ハッシュ スロット パーティショニング アルゴリズムを含む 3 つの一般的に使用されるデータ シャーディング アルゴリズムと、Redis クラスターでのそれらのアプリケーションについて説明します。
-
Docker シミュレーションに基づいた Redis クラスターの構築: Docker コンテナー テクノロジーを使用して、ターゲット トポロジの作成からコンテナーの起動、クラスターの作成まで、Redis クラスターの構築をシミュレートする方法を示します。
-
クラスター障害の処理: Redis クラスターのマスター ノードのダウンタイムと自動転送の原理、およびクラスターの可用性を確保するためにダウンしたマスター ノードを回復する方法について詳しく説明します。
-
クラスターの拡張と縮小: クラスターに新しいノードを追加して拡張する方法を紹介し、さまざまなシナリオのニーズを満たすためにスレーブ ノードとマスター ノードを削除して縮小する方法について説明します。
この記事を読むと、Redis Cluster のクラスター モードをより深く理解し、実際のアプリケーションで Redis Cluster を使用して高可用性とスケーラブルな Redis クラスターを構築できるようになります。