在Kubernetes上构建Redis集群时需要考虑的事项,包括多个区域及区域中的Redis类

以下是在Kubernetes集群上使用多可用区域(MZR)部署Redis Cluster时需要考虑的要点备忘录。

Redis 不仅可作为内存缓存替代 memcached,还能将数据保存在持久卷中。在应用 Kubernetes 进行微服务化和现代化的过程中,轻量高速的 Redis 被视为重要的配置部分之一。另外,在引用的 “The Twelve-Factor Apps” 的第VI条中,建议将会话状态数据保存在像 Redis 这样的数据存储中。因此,在 Kubernetes 集群中,我们需要掌握如何在高可用性和性能方面有效利用 Redis 的技巧。

The Twelve-Factor Apps  https://12factor.net/ja/processes

VI. プロセス
  アプリケーションを1つもしくは複数のステートレスなプロセスとして実行する

抜粋
Webシステムの中には、“スティッキーセッション”に頼るものがある – これはユーザーのセッションデータを
アプリケーションプロセスのメモリにキャッシュし、同じ訪問者からの将来のリクエストが同じプロセスに送ら
れることを期待するものである。スティッキーセッションはTwelve-Factorに違反しており、決して使ったり
頼ったりしてはならない。セッション状態のデータは、有効期限を持つデータストア(例:Memcached や 
Redis)に格納すべきである。 

在可靠性和性能方面,使用”Redis集群”或”Redis和Sentinel”是常见的。在云计算中,通常会通过将多个数据中心放置在一个地区(区域)内,形成可用区来保证高可用性。这种方法不仅可以对数据中心级别的故障进行应对,还可以在广域灾害中产生一定的效果。即使一个数据中心因为严重故障等原因长时间无法使用,我们仍然可以期望在剩余的数据中心中继续进行业务。

本文主要验证在将Redis集群部署在多个数据中心的多区域(Multi-zone)情况下,所面临的问题和实现方法。

关于分区和Redis Cluster的配置想法。

Redis是一个键值存储数据存储器,可以通过指定键来进行数据的注册和获取。在Redis集群中,有多个哈希槽,通过键的哈希来分布存储数据。例如,最小配置下使用三个Redis主节点。为了保证数据的完整性,Redis从节点负责存储Redis主节点数据的副本。

如果发生了以下情况之一,即三个Redis主机中的一个由于某种故障而丢失,那么通过此结构,从节点将被晋升为主节点,以继续提供Redis集群的功能。另一方面,如果Redis的主节点同时停止了两个或更多,那么将停止集群功能,并停止读取和写入操作。

在构成案例1中,将主节点分散放置在不同的区域,同时也将从节点放置在同一区域。

将Redis主节点分散并部署在不同区域,并在每个区域内部署从节点作为配置示例。在这种配置中,如果其中一个区域停止运行,那么某个数据范围即一个槽的数据将会丢失。结果是Redis集群将无法正常工作,无法写入或读取数据。因此,配置方案1是在构建Redis集群时应避免的配置,可以称之为反模式。

Redis-Cluster-Case-1.png

将Master分散配置在Case 2区域中,将Slave配置在其他区域中。

此配置方案可以防止丢失重要数据。Redis集群将数据分散存储在多个哈希槽中。需要在每个槽单元中设置主节点,在该方案中,将主节点分布在Zone-1至3中。每个槽范围的从节点将保持Redis主节点数据的副本在其他区域上。使用这种配置,即使某个区域停止,服务也能继续运行。而且,在三个区域中,即使有两个区域处于灾难状态,数据也可以恢复为可读写状态。

Redis-Cluster-Case-2.png

将该案例分成3个区域,并在每个区域中分散配置主节点,为每个 Redis 节点分配一个 K8s 节点。

在之前的配置中,多个Redis节点在一个K8s节点上运行。而在配置案例3中,Redis节点和K8s节点一对一地运行。复制的方向与配置案例2相同,跨区实施。在这种情况下,除了配置案例2的特点外,还可以减轻K8s节点故障的影响。然而,增加K8s节点会导致云服务费用上升,因此需要考虑必要性和成本的平衡。

Redis-Cluster-Case-3.png

在所列构成案例中,具有成本和数据保全性平衡的是构成案例2,因此,在实际验证过程中确认它。

在多区域中使用状态全量设置的编写方法

使用K8s的StatefulSet控制器构建Redis集群非常方便。它可以按顺序管理Pod的启动和停止,并执行Pod数量的增加和减少,并且能够一起部署持久化卷。

然而,在使用StatefulSet控制器在多区域环境中时,在IKS上可能会遇到麻烦。这是因为StatefulSet的启动Pod和持久化卷的区域没有必要匹配。例如,Pod可能按指定在区域1启动,但是持久化卷却在区域2进行配置的问题。

通过为StatefulSet的清单添加以下标签,可以避免这个问题。为什么通过添加”region”和”zone”标签可以控制持久卷的供应位置还不清楚。可能是因为存储类中定义的供应商正在引用这些标签。整个清单代码可以在GitHub的https://github.com/takara9/redis-cluster/tree/master/iks-mzr-tok-multi-pod 中找到。

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: redis-cluster-1
  labels:
    app: redis-cluster
spec:
  serviceName: redis-cluster
  replicas: 3
  selector:
    matchLabels:
      app: redis-cluster
      region: jp-tok  ## これら二つのラベルを追加する  
      zone: tok05     ## zone値は以下のnodeSelectorの値と一致しなくてはならない。
  template:
    metadata:
      labels:
        app: redis-cluster
        antiaffinity: redis-node
        region: jp-tok  ## こちらにも、同じキーと値のセットのラベルを書いておく。
        zone: tok05     ##
    spec:
      # ノードセレクターで、ポッドがデプロイされるゾーンを指定する。
      # しかし、これだけでは永続ボリュームの配置先は同一リージョン内で不定となる。
      nodeSelector:
        failure-domain.beta.kubernetes.io/zone: tok05
<以下省略>

多区域 + 多节点 构建方法

在多个区域中启动Redis集群的清单已经放在GitHub的以下URL上,请您确认一下清单。
https://github.com/takara9/redis-cluster/tree/master/iks-mzr-tok-multi-pod

从配置映射和服务中应用。

$ kubectl apply -f redis-configmap.yml
configmap/redis-cluster created

$ kubectl apply -f redis-service.yml
service/redis-cluster created

首先,在两个区域中创建一个状态集合。

$ kubectl apply -f redis-cluster-mzr-1m.yml
statefulset.apps/redis-cluster-1 created
$ kubectl apply -f redis-cluster-mzr-2m.yml
statefulset.apps/redis-cluster-2 created

imac:iks-mzr-tok maho$ kubectl get po
NAME                READY   STATUS    RESTARTS   AGE
redis-cluster-1-0   1/1     Running   0          28m
redis-cluster-1-1   1/1     Running   0          26m
redis-cluster-1-2   1/1     Running   0          24m
redis-cluster-2-0   1/1     Running   0          28m
redis-cluster-2-1   1/1     Running   0          26m
redis-cluster-2-2   1/1     Running   0          24m

创建Redis集群的主节点和从节点

使用 redis-cluster-1-0 在 Redis 上执行管理命令 redis-cli,创建最小规模的集群。
Redis 的主节点和从节点将由 Redis 自动确定。在此过程中,将自动将主节点聚集到一个区域中。
如果无法正确分配区域,则在启动集群后需要手动执行故障转移,将其集中到一个区域中。

$ kubectl exec -it redis-cluster-1-0 -- redis-cli --cluster create --cluster-replicas 1 $(kubectl get pods -l 'app=redis-cluster' -o jsonpath='{range.items[*]}{.status.podIP}:6379 ')
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 172.30.155.83:6379 to 172.30.46.203:6379
Adding replica 172.30.155.84:6379 to 172.30.46.204:6379
Adding replica 172.30.155.82:6379 to 172.30.46.205:6379
< 中略 >
..
>>> Performing Cluster Check (using node 172.30.46.203:6379)
M: 7e9ab7262b2c48211afdce8e95c511a0296d0a1b 172.30.46.203:6379
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
M: 47bb522b281cc046346fda7d29727d0f54f9e766 172.30.46.204:6379
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
S: cf7ef722d2b5248eb22f8058f3cba9c06582c3fc 172.30.155.82:6379
   slots: (0 slots) slave
   replicates 1f27ff665a44590151ea356a7879cf391ab54636
M: 1f27ff665a44590151ea356a7879cf391ab54636 172.30.46.205:6379
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
S: 430c82e5ba4173661c3776da7cda2443c5e4de81 172.30.155.84:6379
   slots: (0 slots) slave
   replicates 47bb522b281cc046346fda7d29727d0f54f9e766
S: 9265e13e2d2218f1649a4f10ef4de04dd6ca2147 172.30.155.83:6379
   slots: (0 slots) slave
   replicates 7e9ab7262b2c48211afdce8e95c511a0296d0a1b
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

当Redis集群的最小集合建立好后,再添加第三个状态集合的区域。

$ kubectl apply -f redis-cluster-mzr-3a.yml
statefulset.apps/redis-cluster-3 configured
imac:iks-mzr-tok maho$ kubectl get po
NAME                READY   STATUS    RESTARTS   AGE
redis-cluster-1-0   1/1     Running   0          32m
redis-cluster-1-1   1/1     Running   0          30m
redis-cluster-1-2   1/1     Running   0          28m
redis-cluster-2-0   1/1     Running   0          32m
redis-cluster-2-1   1/1     Running   0          30m
redis-cluster-2-2   1/1     Running   0          28m
redis-cluster-3-0   1/1     Running   0          3m52s
redis-cluster-3-1   1/1     Running   0          3m30s
redis-cluster-3-2   1/1     Running   0          3m12s

在第三个区域的Pod中,通过指定每个槽位的Redis主节点ID来配置Redis从节点。

将 redis-cluster-3-0 设为 redis-cluster-1-0 的从节点。

$ kubectl exec redis-cluster-1-0 -- redis-cli --cluster add-node --cluster-slave --cluster-master-id 7e9ab7262b2c48211afdce8e95c511a0296d0a1b $(kubectl get pod redis-cluster-3-0 -o jsonpath='{.status.podIP}'):6379  $(kubectl get pod redis-cluster-1-0 -o jsonpath='{.status.podIP}'):6379

将 redis-cluster-3-1 设置为 redis-cluster-1-1 的从节点。

$ kubectl exec redis-cluster-1-0 -- redis-cli --cluster add-node --cluster-slave --cluster-master-id 47bb522b281cc046346fda7d29727d0f54f9e766 $(kubectl get pod redis-cluster-3-1 -o jsonpath='{.status.podIP}'):6379  $(kubectl get pod redis-cluster-1-0 -o jsonpath='{.status.podIP}'):6379

将redis-cluster-3-2作为redis-cluster-1-2的从节点。

$ kubectl exec redis-cluster-1-0 -- redis-cli --cluster add-node --cluster-slave --cluster-master-id 1f27ff665a44590151ea356a7879cf391ab54636 $(kubectl get pod redis-cluster-3-2 -o jsonpath='{.status.podIP}'):6379  $(kubectl get pod redis-cluster-1-0 -o jsonpath='{.status.podIP}'):6379

Redis集群有3个区域构成。

通过以上操作,Redis主节点 x3(槽位),从节点(副本)x3(槽位)x2(区域)的设置已完成。

$ kubectl exec redis-cluster-1-0 -- redis-cli -c cluster nodes (実際は順不同、見やすさのため並べかえ済み)
7e9ab7262b2c48211afdce8e95c511a0296d0a1b 172.30.46.203:6379@16379 myself,master - 0 1564886560000 1 connected 0-5460
47bb522b281cc046346fda7d29727d0f54f9e766 172.30.46.204:6379@16379 master - 0 1564886563000 2 connected 5461-10922
1f27ff665a44590151ea356a7879cf391ab54636 172.30.46.205:6379@16379 master - 0 1564886565207 3 connected 10923-16383
cf7ef722d2b5248eb22f8058f3cba9c06582c3fc 172.30.155.82:6379@16379 slave 1f27ff665a44590151ea356a7879cf391ab54636 0 1564886566212 4 connected
9265e13e2d2218f1649a4f10ef4de04dd6ca2147 172.30.155.83:6379@16379 slave 7e9ab7262b2c48211afdce8e95c511a0296d0a1b 0 1564886564206 5 connected
430c82e5ba4173661c3776da7cda2443c5e4de81 172.30.155.84:6379@16379 slave 47bb522b281cc046346fda7d29727d0f54f9e766 0 1564886563000 6 connected
8185dfc3e13fffe360235e04c32b822fccdafffa 172.30.190.208:6379@16379 slave 7e9ab7262b2c48211afdce8e95c511a0296d0a1b 0 1564886562000 1 connected
abc6d8ca61162829429bac9fcc8f4d6d9ef79438 172.30.190.209:6379@16379 slave 47bb522b281cc046346fda7d29727d0f54f9e766 0 1564886563217 2 connected
eccce1ad7408e85a8f941d0e1875750503844b58 172.30.190.210:6379@16379 slave 1f27ff665a44590151ea356a7879cf391ab54636 0 1564886564000 3 connected

在这种情况下,区域1的节点集合为Redis主节点。为了了解在当前状态下的使用情况,我们决定保持当前状态,在进行模拟故障测试之前进行实施。

Redis-Cluster-Case-2-inital.png

从Redis客户端的访问

redis-cluster的有状态集合是根据每个区域部署的,并创建了3个有状态集合。
与此同时,redis-cluster的服务已设置标签和选择器以返回3个区域中9个Pod的IP地址。
详细信息请参阅GitHub上的清单。

$ kubectl get po -l redis-cluster
No resources found.
imac:iks-mzr-tok-multi-pod maho$ kubectl get po -o wide -l app=redis-cluster
NAME                READY   STATUS    RESTARTS   AGE     IP               NODE         
redis-cluster-1-0   1/1     Running   0          3h57m   172.30.46.203    10.193.10.58
redis-cluster-1-1   1/1     Running   0          3h57m   172.30.46.204    10.193.10.58
redis-cluster-1-2   1/1     Running   0          3h56m   172.30.46.205    10.193.10.58
redis-cluster-2-0   1/1     Running   0          3h52m   172.30.155.82    10.192.57.161
redis-cluster-2-1   1/1     Running   0          3h51m   172.30.155.83    10.192.57.161
redis-cluster-2-2   1/1     Running   0          3h51m   172.30.155.84    10.192.57.161
redis-cluster-3-0   1/1     Running   0          4h23m   172.30.190.208   10.212.5.223
redis-cluster-3-1   1/1     Running   0          4h20m   172.30.190.209   10.212.5.223
redis-cluster-3-2   1/1     Running   0          4h18m   172.30.190.210   10.212.5.223

$ kubectl get svc redis-cluster
NAME            TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)              AGE
redis-cluster   ClusterIP   None         <none>        6379/TCP,16379/TCP   22h

$ kubectl get ep redis-cluster
NAME            ENDPOINTS                                                               AGE
redis-cluster   172.30.155.82:6379,172.30.155.33:6379,172.30.155.84:6379 + 15 more...   22h

$ kubectl describe ep redis-cluster
Name:         redis-cluster
Namespace:    default
Labels:       app=redis-cluster
Annotations:  <none>
Subsets:
  Addresses:          172.30.155.82,172.30.155.83,172.30.155.84,172.30.190.208,172.30.190.209,172.30.190.210,172.30.46.203,172.30.46.204,172.30.46.205
  NotReadyAddresses:  <none>
  Ports:
    Name    Port   Protocol
    ----    ----   --------
    client  6379   TCP
    gossip  16379  TCP

Events:  <none>

Redis容器映像中已經安裝了redis-cli,我們可以以互動方式啟動並連線到Redis集群服務。我們可以進行寫入和讀取測試。使用服務名稱進行訪問,並向返回的Pod IP地址提問,如果這是另一個哈希槽,則會返回重定向消息。在重定向位置進行數據的寫入或讀取操作。

$ kubectl run redis-cli --image redis --restart=Never
$ kubectl exec -it redis-cli -- bash
root@redis-cluster-1-0:/data# redis-cli -c -h redis-cluster -p 6379
redis-cluster:6379> set key-a 1001
-> Redirected to slot [6672] located at 172.30.46.204:6379
OK
172.30.46.204:6379> set key-b 2042
OK
172.30.46.204:6379> set key-c 3408
-> Redirected to slot [14930] located at 172.30.46.205:6379
OK
172.30.46.205:6379> get key-a
-> Redirected to slot [6672] located at 172.30.46.204:6379
"1001"
172.30.46.204:6379> get key-b
"2042"
172.30.46.204:6379> get key-c
-> Redirected to slot [14930] located at 172.30.46.205:6379
"3408"

在实际的应用中,可以通过编程语言的库实现以上操作。

模拟区域故障的恢复(主服务器集中在特定区域的情况)

由于重新创建了Redis集群,请注意Pod的IP地址已更改。请验证发生故障、通信不可用时在一个数据中心(即区域)的行为。通过模拟区域故障,删除所有属于存在Redis主服务器的区域的Pod。换句话说,在以下示例中,redis-cluster-2-*的所有Pod都将消失。

在初期阶段,redis-cluster-2-* 存在着主节点。

$ kubectl get po -o wide
NAME                READY   STATUS    RESTARTS   AGE    IP               NODE        
redis-cluster-1-0   1/1     Running   0          112s   172.30.46.227    10.193.10.58
redis-cluster-1-1   1/1     Running   0          92s    172.30.46.228    10.193.10.58
redis-cluster-1-2   1/1     Running   0          74s    172.30.46.229    10.193.10.58
redis-cluster-2-0   1/1     Running   0          44m    172.30.155.89    10.192.57.161
redis-cluster-2-1   1/1     Running   0          42m    172.30.155.90    10.192.57.161
redis-cluster-2-2   1/1     Running   0          40m    172.30.155.91    10.192.57.161
redis-cluster-3-0   1/1     Running   0          27m    172.30.190.215   10.212.5.223
redis-cluster-3-1   1/1     Running   0          25m    172.30.190.216   10.212.5.223
redis-cluster-3-2   1/1     Running   0          23m    172.30.190.217   10.212.5.223

$ kubectl exec -it redis-cluster-2-0 -- redis-cli -c cluster nodes (見やすくするために、IPアドレスでソートしています。)
a42b74b5a3f8002aac192c9e936c28382ab4fca9 172.30.155.89:6379@16379 myself,master - 0 1564909420000 7 connected 10923-16383
a1bc886c988fb43538c96cf64261470d2b0a3070 172.30.155.90:6379@16379 master - 0 1564909420000 8 connected 0-5460
07fbf589aff23033581264a9734d8bd7d6a0c570 172.30.155.91:6379@16379 master - 0 1564909420000 9 connected 5461-10922
ff0d4b630bfbc015a192db93911d4c27d9ccc0fa 172.30.46.227:6379@16379 slave a1bc886c988fb43538c96cf64261470d2b0a3070 0 1564909422477 8 connected
4aab750764825dadf4fddb67eaf7c2df6101195d 172.30.46.228:6379@16379 slave 07fbf589aff23033581264a9734d8bd7d6a0c570 0 1564909421000 9 connected
643ac620d961badfef08c39e815724503dbd53de 172.30.46.229:6379@16379 slave a42b74b5a3f8002aac192c9e936c28382ab4fca9 0 1564909420000 7 connected
31c819ff92f73294c47480e7107d2cbaf2df1c42 172.30.190.215:6379@16379 slave a1bc886c988fb43538c96cf64261470d2b0a3070 0 1564909421470 8 connected
a93fbcda1dd4ff810aa39717195ddbfb1cc7292a 172.30.190.216:6379@16379 slave 07fbf589aff23033581264a9734d8bd7d6a0c570 0 1564909422000 9 connected
19dcb21943fcbdb6244052f2f76ba2dc652900bd 172.30.190.217:6379@16379 slave a42b74b5a3f8002aac192c9e936c28382ab4fca9 0 1564909423482 7 connected

模拟发生故障 (Mó nǐ fā gù

删除了 redis-cluster-2-* 系列的所有Pod。

$ kubectl delete -f redis-cluster-mzr-2m.yml
statefulset.apps "redis-cluster-2" deleted

$ kubectl get po -o wide
NAME                READY   STATUS    RESTARTS   AGE     IP               NODE           NOMINATED NODE   READINESS GATES
redis-cluster-1-0   1/1     Running   0          2m55s   172.30.46.227    10.193.10.58   <none>           <none>
redis-cluster-1-1   1/1     Running   0          2m35s   172.30.46.228    10.193.10.58   <none>           <none>
redis-cluster-1-2   1/1     Running   0          2m17s   172.30.46.229    10.193.10.58   <none>           <none>
redis-cluster-3-0   1/1     Running   0          28m     172.30.190.215   10.212.5.223   <none>           <none>
redis-cluster-3-1   1/1     Running   0          26m     172.30.190.216   10.212.5.223   <none>           <none>
redis-cluster-3-2   1/1     Running   0          24m     172.30.190.217   10.212.5.223   <none>           <none>

Redis主节点全部宕机了。

$ kubectl exec -it redis-cluster-1-0 -- redis-cli -c cluster nodes
a42b74b5a3f8002aac192c9e936c28382ab4fca9 172.30.155.89:6379@16379 master,fail? - 1564909448754 1564909446000 7 connected 10923-16383
a1bc886c988fb43538c96cf64261470d2b0a3070 172.30.155.90:6379@16379 master,fail? - 1564909448855 1564909445000 8 connected 0-5460
07fbf589aff23033581264a9734d8bd7d6a0c570 172.30.155.91:6379@16379 master,fail? - 1564909448754 1564909446950 9 connected 5461-10922
ff0d4b630bfbc015a192db93911d4c27d9ccc0fa 172.30.46.227:6379@16379 myself,slave a1bc886c988fb43538c96cf64261470d2b0a3070 0 1564909465000 1 connected
4aab750764825dadf4fddb67eaf7c2df6101195d 172.30.46.228:6379@16379 slave 07fbf589aff23033581264a9734d8bd7d6a0c570 0 1564909464019 9 connected
643ac620d961badfef08c39e815724503dbd53de 172.30.46.229:6379@16379 slave a42b74b5a3f8002aac192c9e936c28382ab4fca9 0 1564909465022 7 connected
31c819ff92f73294c47480e7107d2cbaf2df1c42 172.30.190.215:6379@16379 slave a1bc886c988fb43538c96cf64261470d2b0a3070 0 1564909467035 8 connected
a93fbcda1dd4ff810aa39717195ddbfb1cc7292a 172.30.190.216:6379@16379 slave 07fbf589aff23033581264a9734d8bd7d6a0c570 0 1564909464000 9 connected
19dcb21943fcbdb6244052f2f76ba2dc652900bd 172.30.190.217:6379@16379 slave a42b74b5a3f8002aac192c9e936c28382ab4fca9 0 1564909466032 7 connected

由于3个Redis主节点停止,集群状态变为停止状态 cluster_state:fail。在Redis集群中,如果同时有2个或更多节点停止,则会导致整个集群停止,这是设计规定。
然而,槽状态仍为正常,可以确定数据没有丢失。
在这种情况下,由于Redis集群已停止,因此无法从客户端进行读取和写入操作。

$ kubectl exec -it redis-cluster-1-0 -- redis-cli -c cluster info
cluster_state:fail
cluster_slots_assigned:16384
cluster_slots_ok:0
cluster_slots_pfail:16384
cluster_slots_fail:0
cluster_known_nodes:9
cluster_size:3
cluster_current_epoch:9
<以下省略>

集群的恢复操作

确认如何从Redis集群因区域故障而停止的状态中恢复Redis服务。

由于Redis集群停止运行,Redis从服务器无法晋升为主服务器。因此,需要通过手动操作将从服务器切换到主服务器。

在下面的示例中,我们执行了两次Redis节点的故障转移操作后,Redis集群恢复正常运行。
但是第三个从服务器已经晋升为主服务器,因此发生了错误。但是这不被视为问题。

执行「cluster failover takeover」命令必须在Redis从节点上进行。
通过此命令,Redis从节点将夺取主节点的权限,并将自己升级为Redis主节点。

由于在1个区域中创建了3个插槽的主节点,因此需要进行以下3个步骤。

imac:iks-mzr-tok-multi-pod maho$ kubectl exec -it redis-cluster-1-0 -- redis-cli -c cluster failover takeover
OK
imac:iks-mzr-tok-multi-pod maho$ kubectl exec -it redis-cluster-1-1 -- redis-cli -c cluster failover takeover
OK
imac:iks-mzr-tok-multi-pod maho$ kubectl exec -it redis-cluster-1-2 -- redis-cli -c cluster failover takeover
(error) ERR You should send CLUSTER FAILOVER to a replica

确认集群恢复后的情况。

发生故障的主服务器保持停止状态,手动进行故障转移的主服务器正在运行中。
当然,如果查看Redis集群状态,cluster_state为”ok”。

$ kubectl exec -it redis-cluster-1-0 -- redis-cli -c cluster nodes (見易さのため IPアドレスでソートしました)
a42b74b5a3f8002aac192c9e936c28382ab4fca9 172.30.155.89:6379@16379 master,fail - 1564909448754 1564909446000 7 connected
a1bc886c988fb43538c96cf64261470d2b0a3070 172.30.155.90:6379@16379 master,fail - 1564909448855 1564909445000 8 connected
07fbf589aff23033581264a9734d8bd7d6a0c570 172.30.155.91:6379@16379 master,fail - 1564909448754 1564909446950 9 connected
ff0d4b630bfbc015a192db93911d4c27d9ccc0fa 172.30.46.227:6379@16379 myself,master - 0 1564909596000 10 connected 0-5460
4aab750764825dadf4fddb67eaf7c2df6101195d 172.30.46.228:6379@16379 master - 0 1564909597569 11 connected 5461-10922
643ac620d961badfef08c39e815724503dbd53de 172.30.46.229:6379@16379 master - 0 1564909596563 12 connected 10923-16383
31c819ff92f73294c47480e7107d2cbaf2df1c42 172.30.190.215:6379@16379 slave ff0d4b630bfbc015a192db93911d4c27d9ccc0fa 0 1564909595562 10 connected
a93fbcda1dd4ff810aa39717195ddbfb1cc7292a 172.30.190.216:6379@16379 slave 4aab750764825dadf4fddb67eaf7c2df6101195d 0 1564909597000 11 connected
19dcb21943fcbdb6244052f2f76ba2dc652900bd 172.30.190.217:6379@16379 slave 643ac620d961badfef08c39e815724503dbd53de 0 1564909598575 12 connected

$ kubectl exec -it redis-cluster-1-0 -- redis-cli -c cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:9
cluster_size:3
cluster_current_epoch:12

处理故障节点

如果被淘汰的区域复活了,它会自动作为从属者重新纳入。

$ kubectl apply -f redis-cluster-mzr-2m.yml
statefulset.apps/redis-cluster-2 created

$ kubectl exec -it redis-cluster-1-0 -- redis-cli -c cluster nodes
a42b74b5a3f8002aac192c9e936c28382ab4fca9 172.30.155.92:6379@16379 slave 643ac620d961badfef08c39e815724503dbd53de 0 1564910872000 12 connected
a1bc886c988fb43538c96cf64261470d2b0a3070 172.30.155.93:6379@16379 slave ff0d4b630bfbc015a192db93911d4c27d9ccc0fa 0 1564910871000 10 connected
07fbf589aff23033581264a9734d8bd7d6a0c570 172.30.155.94:6379@16379 slave 4aab750764825dadf4fddb67eaf7c2df6101195d 0 1564910874024 11 connected
ff0d4b630bfbc015a192db93911d4c27d9ccc0fa 172.30.46.227:6379@16379 myself,master - 0 1564910873000 10 connected 0-5460
4aab750764825dadf4fddb67eaf7c2df6101195d 172.30.46.228:6379@16379 master - 0 1564910872014 11 connected 5461-10922
643ac620d961badfef08c39e815724503dbd53de 172.30.46.229:6379@16379 master - 0 1564910870005 12 connected 10923-16383
31c819ff92f73294c47480e7107d2cbaf2df1c42 172.30.190.215:6379@16379 slave ff0d4b630bfbc015a192db93911d4c27d9ccc0fa 0 1564910873020 10 connected
a93fbcda1dd4ff810aa39717195ddbfb1cc7292a 172.30.190.216:6379@16379 slave 4aab750764825dadf4fddb67eaf7c2df6101195d 0 1564910875028 11 connected
19dcb21943fcbdb6244052f2f76ba2dc652900bd 172.30.190.217:6379@16379 slave 643ac620d961badfef08c39e815724503dbd53de 0 1564910870000 12 connected

模拟区域故障的恢复(Redis主节点被分布在各个区域的情况下)

最初的状态是,Redis主节点集中在redis-cluster-1-*。换句话说,它们集中在Zone-1。

$ kubectl exec -it redis-cluster-1-0 -- redis-cli -c cluster nodes
ff0d4b630bfbc015a192db93911d4c27d9ccc0fa 172.30.46.227:6379@16379 myself,master - 0 1564968490000 10 connected 0-5460
4aab750764825dadf4fddb67eaf7c2df6101195d 172.30.46.228:6379@16379 master - 0 1564968490405 11 connected 5461-10922
643ac620d961badfef08c39e815724503dbd53de 172.30.46.229:6379@16379 master - 0 1564968489000 12 connected 10923-16383
31c819ff92f73294c47480e7107d2cbaf2df1c42 172.30.190.215:6379@16379 slave ff0d4b630bfbc015a192db93911d4c27d9ccc0fa 0 1564968491414 10 connected
a93fbcda1dd4ff810aa39717195ddbfb1cc7292a 172.30.190.216:6379@16379 slave 4aab750764825dadf4fddb67eaf7c2df6101195d 0 1564968493419 11 connected
19dcb21943fcbdb6244052f2f76ba2dc652900bd 172.30.190.217:6379@16379 slave 643ac620d961badfef08c39e815724503dbd53de 0 1564968492417 12 connected
a42b74b5a3f8002aac192c9e936c28382ab4fca9 172.30.155.92:6379@16379 slave 643ac620d961badfef08c39e815724503dbd53de 0 1564968491000 12 connected
a1bc886c988fb43538c96cf64261470d2b0a3070 172.30.155.93:6379@16379 slave ff0d4b630bfbc015a192db93911d4c27d9ccc0fa 0 1564968491000 10 connected
07fbf589aff23033581264a9734d8bd7d6a0c570 172.30.155.94:6379@16379 slave 4aab750764825dadf4fddb67eaf7c2df6101195d 0 1564968487000 11 connected

$ kubectl get po -o wide
NAME                READY   STATUS    RESTARTS   AGE   IP               NODE            NOMINATED NODE   READINESS GATES
redis-cluster-1-0   1/1     Running   0          16h   172.30.46.227    10.193.10.58    <none>           <none>
redis-cluster-1-1   1/1     Running   0          16h   172.30.46.228    10.193.10.58    <none>           <none>
redis-cluster-1-2   1/1     Running   0          16h   172.30.46.229    10.193.10.58    <none>           <none>
redis-cluster-2-0   1/1     Running   0          16h   172.30.155.92    10.192.57.161   <none>           <none>
redis-cluster-2-1   1/1     Running   0          16h   172.30.155.93    10.192.57.161   <none>           <none>
redis-cluster-2-2   1/1     Running   0          16h   172.30.155.94    10.192.57.161   <none>           <none>
redis-cluster-3-0   1/1     Running   0          16h   172.30.190.215   10.212.5.223    <none>           <none>
redis-cluster-3-1   1/1     Running   0          16h   172.30.190.216   10.212.5.223    <none>           <none>
redis-cluster-3-2   1/1     Running   0          16h   172.30.190.217   10.212.5.223    <none>           <none>

以下是对该终端的操作记录的处理结果:通过执行以下命令,将172.30.46.228:6379的5461-10922数据迁移到redis-cluster-2-1 172.30.155.93,并将172.30.46.229:6379的10923-16383数据迁移到redis-cluster-3-2 172.30.190.217。根据结果可以看出,Redis主节点已经被成功迁移。

$ kubectl exec -it redis-cluster-2-1 -- redis-cli -c cluster failover 
OK
$ kubectl exec -it redis-cluster-3-2 -- redis-cli -c cluster failover 
OK
$ kubectl exec -it redis-cluster-1-0 -- redis-cli -c cluster nodes
31c819ff92f73294c47480e7107d2cbaf2df1c42 172.30.190.215:6379@16379 slave a1bc886c988fb43538c96cf64261470d2b0a3070 0 1564968794000 13 connected
a93fbcda1dd4ff810aa39717195ddbfb1cc7292a 172.30.190.216:6379@16379 slave 4aab750764825dadf4fddb67eaf7c2df6101195d 0 1564968791638 11 connected
19dcb21943fcbdb6244052f2f76ba2dc652900bd 172.30.190.217:6379@16379 master - 0 1564968792641 14 connected 10923-16383
ff0d4b630bfbc015a192db93911d4c27d9ccc0fa 172.30.46.227:6379@16379 myself,slave a1bc886c988fb43538c96cf64261470d2b0a3070 0 1564968793000 10 connected
4aab750764825dadf4fddb67eaf7c2df6101195d 172.30.46.228:6379@16379 master - 0 1564968792000 11 connected 5461-10922
643ac620d961badfef08c39e815724503dbd53de 172.30.46.229:6379@16379 slave 19dcb21943fcbdb6244052f2f76ba2dc652900bd 0 1564968794648 14 connected
a42b74b5a3f8002aac192c9e936c28382ab4fca9 172.30.155.92:6379@16379 slave 19dcb21943fcbdb6244052f2f76ba2dc652900bd 0 1564968792000 14 connected
a1bc886c988fb43538c96cf64261470d2b0a3070 172.30.155.93:6379@16379 master - 0 1564968791000 13 connected 0-5460
07fbf589aff23033581264a9734d8bd7d6a0c570 172.30.155.94:6379@16379 slave 4aab750764825dadf4fddb67eaf7c2df6101195d 0 1564968795653 11 connected

进行模拟故障测试

在进行模拟故障测试之前,我们需要进行初始状态确认。确认”cluster_state:ok”显示集群正常运行。然后,将删除redis-cluster-1-*的相关Pod。

$ kubectl exec -it redis-cluster-1-0 -- redis-cli -c cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
<以下省略>

$ kubectl delete -f redis-cluster-mzr-1m.yml
statefulset.apps "redis-cluster-1" deleted

确认状态

可以通过”cluster_state:ok”来确认即使Zone 1的Pod消失了,服务依然正常运行。

$ kubectl get po -o wide
NAME                READY   STATUS    RESTARTS   AGE   IP               NODE         
redis-cluster-2-0   1/1     Running   0          16h   172.30.155.92    10.192.57.161
redis-cluster-2-1   1/1     Running   0          16h   172.30.155.93    10.192.57.161
redis-cluster-2-2   1/1     Running   0          16h   172.30.155.94    10.192.57.161
redis-cluster-3-0   1/1     Running   0          16h   172.30.190.215   10.212.5.223
redis-cluster-3-1   1/1     Running   0          16h   172.30.190.216   10.212.5.223
redis-cluster-3-2   1/1     Running   0          16h   172.30.190.217   10.212.5.223

$ kubectl exec -it redis-cluster-2-0 -- redis-cli -c cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
<以下省略>

以下是一个列出Redis节点的显示。如果在这里发生了双重故障,并且redis-cluster-2系列停止了,显然可以推断出Redis集群将停止。

$ kubectl exec -it redis-cluster-2-0 -- redis-cli -c cluster nodes

ff0d4b630bfbc015a192db93911d4c27d9ccc0fa 172.30.46.227:6379@16379 slave,fail a1bc886c988fb43538c96cf64261470d2b0a3070 1564968882898 1564968880493 13 connected
4aab750764825dadf4fddb67eaf7c2df6101195d 172.30.46.228:6379@16379 master,fail - 1564968882899 1564968882499 11 connected
643ac620d961badfef08c39e815724503dbd53de 172.30.46.229:6379@16379 slave,fail 19dcb21943fcbdb6244052f2f76ba2dc652900bd 1564968882898 1564968881000 14 connected
a42b74b5a3f8002aac192c9e936c28382ab4fca9 172.30.155.92:6379@16379 myself,slave 19dcb21943fcbdb6244052f2f76ba2dc652900bd 0 1564968978000 7 connected
a1bc886c988fb43538c96cf64261470d2b0a3070 172.30.155.93:6379@16379 master - 0 1564968979845 13 connected 0-5460
07fbf589aff23033581264a9734d8bd7d6a0c570 172.30.155.94:6379@16379 master - 0 1564968977838 15 connected 5461-10922
31c819ff92f73294c47480e7107d2cbaf2df1c42 172.30.190.215:6379@16379 slave a1bc886c988fb43538c96cf64261470d2b0a3070 0 1564968979000 13 connected
a93fbcda1dd4ff810aa39717195ddbfb1cc7292a 172.30.190.216:6379@16379 slave 07fbf589aff23033581264a9734d8bd7d6a0c570 0 1564968980849 15 connected
19dcb21943fcbdb6244052f2f76ba2dc652900bd 172.30.190.217:6379@16379 master - 0 1564968981851 14 connected 10923-16383

总结

在微服务化的过程中,人们往往只关注Istio,但对于云原生应用来说,无状态化是一个重要的服务。Redis并不是通过将其分布在云中的多个区域,即多个数据中心,来提高可用性和数据保持性的解决方案。在考虑好容器软件与多区域部署要求的前提下,我们才能确定K8s对象的配置。

而在应用层面进行集群化配置的软件,如Redis,在Kubernetes上也需要充分考虑。Red Hat提出的Operator正是为了减轻这种系统管理的负担。我想尽快安排时间进行确认。

请提供相关参考资料

    • 動的プロビジョニング: ステートフル・セット作成時の PVC の作成, https://cloud.ibm.com/docs/containers?topic=containers-file_storage#file_dynamic_statefulset

Redisクラスタのチュートリアル,https://redis.io/topics/cluster-tutorial

Redisのコマンドライン・クライアント,https://redis.io/topics/rediscli

Redisコマンド,https://redis.io/commands

广告
将在 10 秒后关闭
bannerAds