コンテナ化された Redis クラスタは、デプロイとスケーリングが容易で、リソースを隔離された空間に保存します。これにより、Redis クラスタのデプロイ、管理、スケールアップ、およびメンテナンスの効率が向上し、Redis クラスタの O&M コストが削減されます。このトピックでは、Container Service for Kubernetes (ACK) Serverless クラスタのエラスティックコンテナインスタンスに Redis クラスタを構築する方法について説明します。
背景情報
Redis インスタンスはクラスタモードで実行できます。このモードでは、Redis はストレージスペースを 16,384 個のハッシュスロットに分割します。Redis クラスタ内の各マスターノードは、特定の数のハッシュスロットで構成されるデータベースシャードを担当します。データエントリを書き込むと、Redis はデータエントリのハッシュスロットを計算し、ハッシュスロットを担当するノードにデータを書き込みます。各マスターノードに 1 つ以上のスレーブノードを追加できます。マスターノードが使用できなくなると、スレーブノードの 1 つが自動的にマスターノードを引き継いでサービスを提供します。
Redis は、クラスタモードで高スループットと可用性を提供します。ただし、Redis はこのモードでもデータ損失を防ぐことはできません。詳細については、Redis 公式ドキュメントを参照してください。
前提条件
以下の条件を満たす ACK Serverless クラスタが作成されていること:
クラスタでインターネットアクセスが有効になっており、クラスタがパブリックイメージをプルできること。
クラスタにストレージプラグインがデプロイされていること。
Container Storage Interface (CSI) プラグインをデプロイすることをお勧めします。Alibaba Cloud CSI-Provisioner コンポーネントが CSI プラグインにデプロイされていることを確認してください。
CoreDNS がクラスタにデプロイされていること。
Redis クラスタを構築する
このトピックでは、公式の Redis イメージ v6.0.8 を例として使用して、3 つのマスターノードと 3 つのスレーブノードを含む 6 つのノードで構成される Redis クラスタを作成します。各ノードにはステータスと識別子があります。Statefulset を使用してポッドを作成できます。ノードデータを永続的に保存するには、各ノードにディスクを接続する必要があります。
Redis v5.0 以降を使用することをお勧めします。5.0 より前の Redis バージョンを使用する場合は、このトピックで提供されているコマンドとは異なるコマンドを使用してクラスタを初期化する必要がある場合があります。
ConfigMap を作成して、Redis クラスタの構成を保存および管理します。
kubectl create -f redis-config.yaml
redis-config.yaml ファイルの内容例:
apiVersion: v1 kind: ConfigMap metadata: name: redis-cluster data: redis.conf: | bind 0.0.0.0 port 6379 cluster-announce-bus-port 16379 cluster-enabled yes appendonly yes cluster-node-timeout 5000 dir /data cluster-config-file /data/nodes.conf requirepass pass123 masterauth pass123
dir
フィールドは、Redis クラスタ内のノードデータの永続ストレージディレクトリを指定します。ポッドの/data
ディレクトリは永続ストレージディレクトリである必要があります。cluster-config-file
フィールドは、Redis クラスタのノード情報を指定します。ノード情報は Redis ノードによって自動的に生成および変更されます。フィールドの値も永続ストレージディレクトリです。ノードに障害が発生した後、クラスタ内の他のノードが障害が発生したノードを引き継いでサービスを提供できます。
ヘッドレスサービスを作成します。
kubectl create -f redis-service.yaml
redis-service.yaml ファイルの内容例:
apiVersion: v1 kind: Service metadata: name: redis-cluster-svc spec: clusterIP: None selector: app: redis-cluster
Statefulset を作成して Redis をデプロイします。
StatefulSet を作成するときは、作成したサービスを参照し、ConfigMap を各ポッドの
/config
ディレクトリにマウントし、各ポッドの永続ボリュームクレーム (PVC) を作成してから、PVC を/data
ディレクトリにマウントします。kubectl create -f redis.yaml
redis.yaml ファイルの内容例:
apiVersion: apps/v1 kind: StatefulSet metadata: name: redis-cluster spec: selector: matchLabels: app: redis-cluster serviceName: redis-cluster-svc replicas: 6 template: metadata: labels: app: redis-cluster alibabacloud.com/eci: "true" spec: terminationGracePeriodSeconds: 10 affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - podAffinityTerm: labelSelector: matchExpressions: - key: app operator: In values: - redis-cluster topologyKey: kubernetes.io/hostname weight: 100 containers: - name: redis image: redis:6.0.8 command: ["redis-server", "/config/redis.conf"] ports: - name: redis containerPort: 6379 protocol: TCP - name: election containerPort: 16379 protocol: TCP volumeMounts: - name: redis-conf mountPath: /config - name: pvc-essd-redis-data mountPath: /data volumes: - name: redis-conf configMap: name: redis-cluster items: - key: redis.conf path: redis.conf volumeClaimTemplates: - metadata: name: pvc-essd-redis-data spec: accessModes: [ "ReadWriteOnce" ] storageClassName: alicloud-disk-essd resources: requests: storage: 20Gi
Statefulset を作成した後、Statefulset 内のすべてのポッドが Ready 状態になるまで待ちます。
kubectl get statefulset redis-cluster -o wide
次のコマンド出力が返されます。
NAME READY AGE CONTAINERS IMAGES redis-cluster 6/6 8m52s redis redis:6.0.8
クラスタを初期化します。
各ノードの IP アドレスを取得します。
Redis では、ホスト名を使用してクラスタを初期化することはできません。Redis クラスタを初期化するときは、各ノードの IP アドレスを取得する必要があります。
kubectl get pods -l app=redis-cluster -o wide
次のコマンド出力が返されます。
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES redis-cluster-0 1/1 Running 0 9m37s 172.16.55.6 virtual-kubelet-cn-beijing-k <none> <none> redis-cluster-1 1/1 Running 0 9m5s 172.16.55.7 virtual-kubelet-cn-beijing-k <none> <none> redis-cluster-2 1/1 Running 0 8m30s 172.16.55.8 virtual-kubelet-cn-beijing-k <none> <none> redis-cluster-3 1/1 Running 0 7m46s 172.16.55.9 virtual-kubelet-cn-beijing-k <none> <none> redis-cluster-4 1/1 Running 0 7m7s 172.16.55.10 virtual-kubelet-cn-beijing-k <none> <none> redis-cluster-5 1/1 Running 0 6m30s 172.16.55.11 virtual-kubelet-cn-beijing-k <none> <none>
Redis ノードのいずれかにログインします。
kubectl exec -ti redis-cluster-0 bash
6 つのノードの初期化コマンドを実行します。
--cluster-replicas
オプションを 1 に設定して、各マスターノードにスレーブノードが割り当てられるようにします。このようにして、クラスタには 3 つのマスターノードと 3 つのスレーブノードが含まれます。redis-cli -a pass123 --cluster create 172.16.55.6:6379 172.16.55.7:6379 172.16.55.8:6379 172.16.55.9:6379 172.16.55.10:6379 172.16.55.11:6379 --cluster-replicas 1
次のコマンド出力が返された場合、クラスタは初期化されます。
[OK] All nodes agree about slots configuration. >>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered.
Redis クラスタを使用します。
ヘッドレスサービスを作成すると、kubernetes クラスタは
{service name}.{service namespace}.svc.{domain}
形式でサービスにドメインネームシステム (DNS) A レコードを割り当てます。DNS レコードはバックエンドポッドの IP アドレスにマップされます。サービス名にアクセスするたびに、サービス名はランダムな Redis ノードに解決されます。これにより、クラスタ内のポッドにアクセスすることで Redis クラスタにアクセスできます。
redis-cli -a pass123 -c -h redis-cluster-svc.default.svc.cluster.local -p 6379
テスト例:
172.16.55.8> set k1 v1 OK 172.16.55.8> get k1 "v1"
Redis クラスタをスケールアップする
次の理由により、Redis クラスタを動的にスケールアップすることはできません。まず、新しいノードが追加されるたびに、Redis はクラスタ内のすべてのノードにハッシュスロットを再割り当てする必要があります。ポッドが起動するたびにハッシュスロットの再割り当てを自動化するスクリプトを Redis イメージに追加できます。ただし、大量のデータがクラスタに追加されると、継続的な再シャーディングによりクラスタのスケールアップが遅くなります。シャーディングは Redis クラスタの帯域幅を使い果たす可能性もあり、Redis に依存するすべてのクライアントがタイムアウトする可能性があります。次に、再起動されたポッドをマスターノードとして使用するかスレーブノードとして使用するかを決定するために使用できる適切なポリシーはありません。
上記の課題に対処するために、次の例では、手動シャーディングを実行して Redis クラスタをスケールアップする方法を示します。
Statefulset のレプリカ数を 6 から 8 に変更します。
kubectl scale statefulsets redis-cluster --replicas=8
新しいノードの IP アドレスを取得します。
すべてのポッドが Ready 状態になったら、次のコマンドを実行して新しいノードの IP アドレスを取得します。
kubectl get pods -l app=redis-cluster -o wide
次のコマンド出力が返されます。redis-cluster-6 と redis-cluster-7 は新しいノードです。
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES redis-cluster-0 1/1 Running 0 88m 172.16.55.6 virtual-kubelet-cn-beijing-k <none> <none> redis-cluster-1 1/1 Running 0 88m 172.16.55.7 virtual-kubelet-cn-beijing-k <none> <none> redis-cluster-2 1/1 Running 0 87m 172.16.55.8 virtual-kubelet-cn-beijing-k <none> <none> redis-cluster-3 1/1 Running 0 87m 172.16.55.9 virtual-kubelet-cn-beijing-k <none> <none> redis-cluster-4 1/1 Running 0 86m 172.16.55.10 virtual-kubelet-cn-beijing-k <none> <none> redis-cluster-5 1/1 Running 0 85m 172.16.55.11 virtual-kubelet-cn-beijing-k <none> <none> redis-cluster-6 1/1 Running 0 52s 172.16.55.16 virtual-kubelet-cn-beijing-k <none> <none> redis-cluster-7 1/1 Running 0 32s 172.16.55.17 virtual-kubelet-cn-beijing-k <none> <none>
マスターノードを追加します。
いずれかのノードにログインします。このトピックでは、redis-cluster-0 にログインします。次のコマンドを実行して、redis-cluster-6 をクラスタのマスターノードとして追加します。
kubectl exec -ti redis-cluster-0 bash
redis-cli -a pass123 --cluster add-node 172.16.55.16:6379 172.16.55.6:6379
説明上記のコマンドで、
172.16.55.6:6379
は既存のノードのアドレスです。ノードに接続すると、redis-cli は自動的に他のノードのアドレスを取得します。redis-cluster-6 の ID をクエリします。
redis-cli -a pass123 -c cluster nodes | grep 172.16.55.16:6379 | awk '{print $1}'
次のコマンド出力が返されます。
47879390ecc7635f5c57d3e324e2134b24******
ハッシュスロットを再割り当てします。
redis-cluster-6 をマスターノードとしてクラスタに追加すると、Redis クラスタには 4 つのマスターノードが存在します。4 つのノードは 16,384 個のハッシュスロットを共有します。各マスターノードには平均で
16,384/4 = 4,096
個のハッシュスロットが割り当てられます。したがって、4,096 個のハッシュスロットを既存の 3 つのマスターノードから新しいマスターノードに移動する必要があります。次のコマンドを実行して、ハッシュスロットを再割り当てします。
172.16.55.6:6379
は既存のノードのアドレスです。ノードに接続すると、redis-cli は自動的に他のノードのアドレスを取得します。redis-cli -a pass123 --cluster reshard 172.16.55.6:6379
上記のコマンドラインインタフェースのプロンプトに基づいて、必要な情報を順番に入力します。
How many slots do you want to move (from 1 to 16384)? 4096 What is the receiving node ID? 47879390ecc7635f5c57d3e324e2134b24****** Source node #1: all Do you want to proceed with the proposed reshard plan (yes/no)? yes
新しいノード (redis-cluster-6) に割り当てるハッシュスロットの数: 4,096
受信ノード (新しいノード) の ID: 47879390ecc7635f5c57d3e324e2134b24******
ソースノード (すべての既存ノード) の ID: all
再割り当ての確認: yes
ハッシュスロットが再割り当てされるまで待ちます。再割り当て中、Redis クラスタは引き続きサービスを提供できます。
スレーブノードを追加します。
次のコマンドを実行して、redis-cluster-7 を redis-cluster-6 のスレーブノードとして追加します。
redis-cli -a pass123 --cluster add-node 172.16.55.17:6379 172.16.55.6:6379 --cluster-slave --cluster-master-id 47879390ecc7635f5c57d3e324e2134b24******
説明上記のコマンドで、
172.16.55.6:6379
は既存のノードのアドレスです。ノードに接続すると、redis-cli は自動的に他のノードのアドレスを取得します。47879390ecc7635f5c57d3e324e2134b24******
はマスターノード (redis-cluster-6) の ID です。
スレーブノードを追加すると、Redis クラスタに 4 つのスレーブノードに対応する 4 つのマスターノードが表示されます。
redis-cli -a pass123 -c cluster nodes
出力例:
47879390ecc7635f5c57d3e324e2134b24****** 172.16.55.16:6379@16379 master - 0 1667383406000 7 connected 0-1364 5461-6826 10923-12287 75a7398a45f9696066eaa6ac7968b13a47****** 172.16.55.11:6379@16379 slave b8f6b826241b47f29a4bdde14104b28fe8****** 0 1667383406514 2 connected b7849f8577e43d5a6da51bc78ae809bbb1****** 172.16.55.17:6379@16379 slave 47879390ecc7635f5c57d3e324e2134b24****** 0 1667383406314 7 connected b8f6b826241b47f29a4bdde14104b28fe8****** 172.16.55.7:6379@16379 master - 0 1667383406815 2 connected 6827-10922 ffce547186e0be179830cb0dca47c203f6****** 172.16.55.6:6379@16379 myself,master - 0 1667383406000 1 connected 1365-5460 833a939cde93991c8a16c41fb2568b8642****** 172.16.55.8:6379@16379 master - 0 1667383406514 3 connected 12288-16383 a4df1a26394bfcb833914278744219db01****** 172.16.55.9:6379@16379 slave 833a939cde93991c8a16c41fb2568b8642****** 0 1667383407515 3 connected c4234d71343ca4dbe07822e17f7572ac30****** 172.16.55.10:6379@16379 slave ffce547186e0be179830cb0dca47c203f6****** 0 1667383405813 1 connected
Redis クラスタをスケールダウンする
Redis クラスタのスケールダウン中、StatefulSet は、ポッドが作成されたのとは逆の順序で、ポッドを 1 つずつ削除することしかできません。マスターノードとスレーブノードを Redis クラスタから削除する場合は、Statefulset を使用して redis-cluster-7 と redis-cluster-6 を削除する必要があります。Redis は、StatefulSet がノードを削除する前に、2 つのノードのすべてのハッシュスロットを他のノードに割り当てる必要があります。そうしないと、データが失われ、Redis クラスタはサービスを拒否します。
ハッシュスロットを再割り当てします。
残りの 3 つのマスターノードの負荷の偏りを防ぐために、StatefulSet は redis-cluster-6 のハッシュスロットを残りのマスターノードに均等に割り当てる必要があります。この場合、Redis は 3 つの再シャーディング操作を実行する必要があります。手順はスケールアップ手順と似ています。ただし、各再シャーディング操作では、受信ノードを残りのマスターノードのいずれかに設定し、ソースノードを redis-cluster-6 に設定する必要があります。コマンド例:
redis-cli -a pass123 --cluster reshard 172.16.55.6:6379
上記のコマンドラインインタフェースのプロンプトに基づいて、必要な情報を順番に入力します。
How many slots do you want to move (from 1 to 16384)? 4096 What is the receiving node ID? ffce547186e0be179830cb0dca47c203f6****** Source node #1: 47879390ecc7635f5c57d3e324e2134b24****** Source node #2: done Do you want to proceed with the proposed reshard plan (yes/no)? yes
残りのマスターノードに割り当てるハッシュスロットの数: 4,096
受信ノード (残りのノードのいずれか) の ID: ffce547186e0be179830cb0dca47c203f6******
ソースノード (redis-cluster-6) の ID: 47879390ecc7635f5c57d3e324e2134b24******
再割り当ての確認: yes
Statefulset のレプリカ数を 8 から 6 に変更します。
kubectl scale statefulsets redis-cluster --replicas=6
Redis クラスタのポッド情報を表示します。クラスタ内のノード数が 6 に減少していることがわかります。
kubectl get pods -l app=redis-cluster -o wide
Redis クラスタを削除する
Redis クラスタを削除するには、StatefulSet、Service、および ConfigMap を削除する必要があります。
kubectl delete statefulset redis-cluster
kubectl delete svc redis-cluster-svc
kubectl delete cm redis-cluster
StatefulSet を削除した後、関連する PVC は自動的に削除されません。PVC は手動で削除する必要があります。PVC を削除すると、対応するディスクとデータも削除されます。
kubectl delete pvc -l app=redis-cluster