すべてのプロダクト
Search
ドキュメントセンター

Elastic Container Instance:エラスティックコンテナインスタンスに Redis クラスタを構築する

最終更新日:Dec 28, 2024

コンテナ化された 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 バージョンを使用する場合は、このトピックで提供されているコマンドとは異なるコマンドを使用してクラスタを初期化する必要がある場合があります。

  1. 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 ノードによって自動的に生成および変更されます。フィールドの値も永続ストレージディレクトリです。ノードに障害が発生した後、クラスタ内の他のノードが障害が発生したノードを引き継いでサービスを提供できます。

  2. ヘッドレスサービスを作成します。

    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
  3. 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
  4. クラスタを初期化します。

    1. 各ノードの 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>
    2. 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.
  5. 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 クラスタをスケールアップする方法を示します。

  1. Statefulset のレプリカ数を 6 から 8 に変更します。

    kubectl scale statefulsets redis-cluster --replicas=8
  2. 新しいノードの 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>
  3. マスターノードを追加します。

    いずれかのノードにログインします。このトピックでは、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******
  4. ハッシュスロットを再割り当てします。

    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 クラスタは引き続きサービスを提供できます。

  5. スレーブノードを追加します。

    次のコマンドを実行して、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 クラスタはサービスを拒否します。

  1. ハッシュスロットを再割り当てします。

    残りの 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

  2. 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