背景信息
Redis支持以集群模式运行,在该模式下,Redis将所有存储空间分为16384个哈希槽,集群中的每个Master节点负责N个哈希槽(一个数据分片),当用户写入一条数据时,Redis计算其哈希槽,然后将数据写在负责该哈希槽的节点上。且每个Master节点可以添加一个或多个Slave节点,当某个Master节点不可用时,其Slave节点自动代替Master节点继续工作。
由此可见,在Redis集群模式下,可以获得更高的吞吐量和一定程度的可用性。需要注意的是,在集群模式下,Redis仍不能保证数据零丢失,更多信息,请参见Redis官方文档。
前提条件
已创建Kubernetes集群,且集群需满足以下条件:
集群具备公网环境,可以通过公网拉取镜像。
集群中已部署存储插件。
集群版本高于1.16时,建议使用CSI插件,需确保已部署天翼云CSI-Provisioner组件。
集群中已部署CoreDNS。
搭建Redis集群
本文以Redis官方镜像6.0.8版本作为示例,创建一个6个节点的Redis集群,其中3个Master节点,3个Slave节点。因为每个节点有自己的状态和标识,所以使用Statefulset来创建Pod,此外需要为每个节点挂载一个云盘,用于持久化存储节点数据。
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节点数据的持久化存储目录,所以Pod的/data目录应当是一个持久化存储目录。
字段cluster-config-file是Redis集群的节点信息,由Redis节点自动生成和修改,该配置也应当是一个持久化存储目录,以便节点宕机恢复后能够找到集群中的其他节点,并继续工作。
2.创建一个headless类型的Service。
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时引用之前创建的Service,将ConfigMap挂载到每一个Pod的/config,并且为每一个Pod创建一个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-clus ctyun.cn/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: ctcloud-disk-essd resources: requests: storage: 20Gi
创建后,等待Statefulset中的所有Pod达到Ready状态。
kubectl get statefulset redis-cluster -o wide
预期返回:
NAME READY AGE CONTAINERS IMAGES redis-cluster 6/6 8m52s redis redis:6.0.8
4.初始化集群地址。
a.获取每个节点的IP地址。
目前Redis还不支持以hostname方式初始化集群,所以需要先获取每个节点的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 9m31s 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 8m20s 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>
b.登录到其中一个Redis节点。
kubectl exec -ti redis-cluster-0 bash
为6个节点执行初始化命令,当选项--cluster-replicas指定为1时,表示为每个Master节点分配一个Slave节点,这样集群中刚好3个Master节点和3个Slave节点。
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。
由于之前创建了一个headless类型的Service,kubernetes集群会为该服务分配一个DNS A记录,格式为{service name}.{service namespace}.svc.{domain},可以映射到后端Pod IP列表,即每次访问该服务名时,将随机解析到其中一个Redis节点上。
因此,进入集群中的任意一个Pod中均可以访问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"