Skip to content

Commit 06aae48

Browse files
authored
Merge pull request #65 from ucloud/feature/design_doc
Feature/design doc
2 parents b46eceb + e31491f commit 06aae48

File tree

7 files changed

+186
-2
lines changed

7 files changed

+186
-2
lines changed

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ redis-cluster-operator 1/1 1 1 1d
9393

9494
#### Deploy a sample Redis Cluster
9595

96+
NOTE: **Only the redis cluster that use persistent storage(pvc) can recover after accidental deletion or rolling update.Even if you do not use persistence(like rdb or aof), you need to set pvc for redis.**
97+
9698
```
9799
$ kubectl apply -f deploy/example/redis.kun_v1alpha1_distributedrediscluster_cr.yaml
98100
```
@@ -168,7 +170,7 @@ spec:
168170

169171
#### Backup and Restore
170172

171-
**Only Ceph object storage is supported now**
173+
NOTE: **Only Ceph S3 object storage and PVC is supported now**
172174

173175
Backup
174176
```
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
apiVersion: v1
2+
kind: PersistentVolumeClaim
3+
metadata:
4+
name: test-backup
5+
spec:
6+
accessModes:
7+
- ReadWriteMany
8+
resources:
9+
requests:
10+
storage: 10Gi
11+
storageClassName: {storageClassName}
12+
volumeMode: Filesystem
13+
---
14+
15+
apiVersion: redis.kun/v1alpha1
16+
kind: RedisClusterBackup
17+
metadata:
18+
name: example-redisclusterbackup
19+
annotations:
20+
redis.kun/scope: cluster-scoped
21+
spec:
22+
image: hub.ucloudadmin.com/uaek/redis-tools:5.0.4
23+
# on same namespace
24+
redisClusterName: test
25+
local:
26+
mountPath: /back
27+
persistentVolumeClaim:
28+
claimName: test-backup

deploy/example/backup-restore/restore.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,4 @@ spec:
99
init:
1010
backupSource:
1111
name: example-redisclusterbackup
12-
namespace: default
12+
namespace: default
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
apiVersion: redis.kun/v1alpha1
2+
kind: DistributedRedisCluster
3+
metadata:
4+
name: restore
5+
spec:
6+
clusterReplicas: 1
7+
config:
8+
appendfsync: everysec
9+
appendonly: "yes"
10+
auto-aof-rewrite-min-size: 64mb
11+
auto-aof-rewrite-percentage: "100"
12+
cluster-node-timeout: "5000"
13+
loglevel: verbose
14+
maxclients: "1000"
15+
maxmemory: "0"
16+
notify-keyspace-events: ""
17+
rdbcompression: "yes"
18+
save: 900 1 300 10
19+
stop-writes-on-bgsave-error: "yes"
20+
tcp-keepalive: "0"
21+
timeout: "0"
22+
image: redis:5.0.4-alpine
23+
masterSize: 3
24+
resources:
25+
limits:
26+
cpu: 400m
27+
memory: 300Mi
28+
requests:
29+
cpu: 400m
30+
memory: 300Mi
31+
storage:
32+
class: {storageClassName}
33+
size: 10Gi
34+
type: persistent-claim
35+
init:
36+
backupSource:
37+
name: example-redisclusterbackup
38+
namespace: default
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# 备份和恢复
2+
3+
目前只支持备份到 ceph S3对象存储及本地 pvc 中。
4+
5+
备份开始时使用 redis-cli 同步 Master 的 RDB到本地后再使用 [Rclone](https://rclone.org/)
6+
RDB 文件传输到对象存储或者 pvc 中,恢复时先使用 Rclone 从之前备份的位置同步备份到本地后,再启动 Redis
7+
服务。备份恢复的工具类镜像中预置了 redis-cli 和 Rclone,参见 [Dockerfile](hack/docker/redis-tools/Dockerfile)
8+
9+
## 备份
10+
11+
Operator 会 Watch 集群所有的 RedisClusterBackup 实例变化,当用户提交一个备份的 CR 之后,Operator 会:
12+
13+
1. 创建一个 Kubernetes batch job,根据 Redis 集群分布数,在 job 中注入相同数量的 container,每个 container 向一个 Master 发起备份请求,设置开始时间及备份状态。
14+
2. 同步完成 RDB 文件后,将 Redis 集群每个分片的 RDB 文件和 cluster-config-file(记录节点slots信息) 上传到对象存储,同时将 CR 的状态置为 Succeeded,设置完成时间。redis集群备份的快照和节点元数据信息,上传到对象存储后,有统一的路径,当前的规则是:redis/{Namespace}/{RedisClusterName}/{StartTime}/{BackupName}-x
15+
比如一个备份一个在 default 命名空间的名为 redis-cluster-test 的 Redis 集群(集群含有三个 master 节点),备份名为 backup , 备份开始时间为 20191101083020,最后会有如下对象存储路径:
16+
17+
```
18+
redis/default/redis-cluster-test/20191101083020/backup-0
19+
redis/default/redis-cluster-test/20191101083020/backup-1
20+
redis/default/redis-cluster-test/20191101083020/backup-2
21+
```
22+
23+
每个master节点备份的快照和节点元数据信息会存储在上述路径,用户可以到相应的 bucket 中查看。
24+
25+
## 从备份恢复
26+
27+
从备份恢复和创建步骤不同,分为两阶段,第一阶段同步数据,从快照启动 Master 节点;第二阶段启动 Slave 节点。
28+
29+
1. 设置`DistributedRedisCluster.Status.Restore.Phase=Running`,根据备份信息,创建与备份集群切片数相同的 Statefulset,
30+
设置 Replicas 为 1,只启动 master 节点,注入 init container,init container 的作用是拉取对象存储上的快照数据。
31+
2. 等待第1步同步数据完成,master 启动完成后,设置`DistributedRedisCluster.Status.Restore.Phase=Restart`,移除
32+
init container 后等待节点重启。
33+
3. 第2步完成之后,增加每个分片的副本数调大 Statefulset 的 Replicas,拉起 Slave 节点,设置`DistributedRedisCluster.Status.Restore.Phase=Succeeded`
34+
等待所有 Pod 节点状态变为 Runing 之后,设置每个 Statefulset 的 Slave 节点 replicate Master 节点,加入集群。

doc/design/zh/cluster_create.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# 创建集群
2+
3+
**需要注意的是,只有配置了持久化存储(PVC)的 CR 实例可以故障自愈**
4+
5+
如用户希望创建 3 分片的集群,每个分片一主一从:
6+
7+
```
8+
apiVersion: redis.kun/v1alpha1
9+
kind: DistributedRedisCluster
10+
metadata:
11+
annotations:
12+
# if your operator run as cluster-scoped, add this annotations
13+
redis.kun/scope: cluster-scoped
14+
name: example-distributedrediscluster
15+
spec:
16+
masterSize: 3 # 三分片
17+
clusterReplicas: 1 # 每个主节点一个从节点
18+
image: redis:5.0.4-alpine
19+
storage:
20+
type: persistent-claim
21+
size: 1Gi
22+
class: {StorageClassName}
23+
deleteClaim: true # 删除 Redis Cluster 时,自动清理 pvc
24+
```
25+
26+
Operator Watch 到新的 Redis Cluster CR 实例被创建时,Operator 会执行以下操作:
27+
28+
1. 为每个分片创建一个 Statefulset,每个 Statefulset Name 后缀以 0,1,2... 递增,设置 Statefulset Replicas 为副本数+1(Master),每个 Statefulset 代表着一个分片及其所有副本,所以将创建 3 个 Statefulset,每个 Statefulset 的 Replicas 为 3,每个 Pod 代表一个 Redis 实例。
29+
2. 等待所有 Pod 状态变为 Ready 且每个节点相互识别后,Operator 会在每个 Statefulset 的 Pod 中挑选一个作为 Master 节点,其余节点为该 Master 的 Slave,并尽可能保证所有 Master 节点不在同一个 k8s node。
30+
3. 为 Master 分配 Slots,将 Slave 加入集群,从而组建集群。
31+
4. 为每一个 Statefulset 创建一个 Headless Service,为整个集群创建一个 Service 指向所有的 pod。
32+
33+
## 亲和性和反亲和性
34+
35+
为保证 Redis CLuster 的高可用性,CRD 中设计了 `affinity``requiredAntiAffinity` (bool) 字段来做 Redis 节点间的打散:
36+
37+
* 当 affinity 和 requiredAntiAffinity 都未设置时,Operator 默认设置 Statefulset 管理的一组 pod 及 所有 pod 尽量反亲和;
38+
* 当用户只设置 requiredAntiAffinity 字段的时,Operator 会设置 Statefulset 管理的一组 pod 强制反亲和,所有 pod 尽量反亲和;
39+
* 当用户设置了 affinity 时,Statefulset 直接继承 affinity,Operator 不做额外设置。

doc/design/zh/cluster_scaling.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Redis Cluster 横向扩容和缩容
2+
3+
## 扩容
4+
5+
当 Operator Watch 到一个 Redis Cluster 需要扩容时,Operator 会:
6+
7+
1. 新建 Statefulset。
8+
2. 等待新的 Pod 状态变为 Ready 且每个节点相互识别后后从新的 Statefulset 选出 Master 节点,其余为 Slave。
9+
3. Operator 调整 Slot,将其他 Statefulset 的 Master 节点的 Slots 调度到新的 Master,尽可能使其平均分布到所有的 Redis 节点上。
10+
11+
以扩容一个节点为例。
12+
numSlots(迁移节点数): 表示扩容时分配到新节点的 slot 数量
13+
numSlots=16384/集群节点。
14+
集群现有的每个 Master 节点待迁移slot数计算公式为:
15+
待迁移slot数量 * (该源节点负责的slot数量 / slot总数)
16+
17+
当前 Master Slots 分布:
18+
```
19+
Master[0] -> Slots 0 - 5460 slots=5461
20+
Master[1] -> Slots 5461 - 10922 slots=5462
21+
Master[2] -> Slots 10923 - 16383 slots=5461
22+
```
23+
加入节点 Master[3],numSlots=16384/4=4096
24+
那么分配到集群现有每个 Master 节点的待迁移 migratingSlots 数为:
25+
```
26+
Master[0] migratingSlots = 4096 * (5461 / 16384) = 1365.25=1365
27+
Master[1] migratingSlots = 4096 * (5462 / 16384) = 1365.5=1366
28+
Master[2] migratingSlots = 4096 * (5461 / 16384) = 1365.25=1365
29+
```
30+
最终:
31+
```
32+
Master[0] -> Slots 1365-5460 slots=4096
33+
Master[1] -> Slots 6827-10922 slots=4096
34+
Master[2] -> Slots 12288-16383 slots=4096
35+
Master[3] -> Slots 0-1364 5461-6826 10923-12287 slots=4096
36+
```
37+
## 缩容
38+
39+
当 Operator Watch 到一个 Redis Cluster 需要缩容时,Operator 会:
40+
41+
1. 将待删除 Statefulset 的 Master 节点所有的 Slots 迁移到其他 Master。
42+
2. 从后缀名最大的 Statefulset 的开始,将其所有的节点踢出集群。
43+
3. 删除 Statefulset 及相关资源。

0 commit comments

Comments
 (0)