xyZGHio

本是青灯不归客,却因浊酒恋风尘

0%

浅谈Redis Cluster 集群的伸缩

本文介绍Redis Cluster模式下集群的伸缩(扩容/缩容)过程进行介绍

abstract.png

搭建集群

利用Docker Compose搭建一个3主3从的Redis Cluster集群,docker-compose.yml文件如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# 构建一个3主3从的Redis集群
# Compose 版本
version: '3.8'

# 定义服务
services:

Redis-Service-1:
image: redis:7.0
container_name: node-1
command: [ "redis-server", "/etc/redis/redis.conf" ]
ports:
- "6371:6379"
- "16371:16379"
volumes:
- /Users/zgh/Docker/RedisCluster_3M3S/RedisConf/redis.conf:/etc/redis/redis.conf
networks:
# 使用名为redis_cluster_3m3s_net的网络并设置容器IP
redis_cluster_3m3s_net:
ipv4_address: 120.120.120.11

Redis-Service-2:
image: redis:7.0
container_name: node-2
command: [ "redis-server", "/etc/redis/redis.conf" ]
ports:
- "6372:6379"
- "16372:16379"
volumes:
- /Users/zgh/Docker/RedisCluster_3M3S/RedisConf/redis.conf:/etc/redis/redis.conf
networks:
# 使用名为redis_cluster_3m3s_net的网络并设置容器IP
redis_cluster_3m3s_net:
ipv4_address: 120.120.120.12

Redis-Service-3:
image: redis:7.0
container_name: node-3
command: [ "redis-server", "/etc/redis/redis.conf" ]
ports:
- "6373:6379"
- "16373:16379"
volumes:
- /Users/zgh/Docker/RedisCluster_3M3S/RedisConf/redis.conf:/etc/redis/redis.conf
networks:
# 使用名为redis_cluster_3m3s_net的网络并设置容器IP
redis_cluster_3m3s_net:
ipv4_address: 120.120.120.13

Redis-Service-4:
image: redis:7.0
container_name: node-4
command: [ "redis-server", "/etc/redis/redis.conf" ]
ports:
- "6374:6379"
- "16374:16379"
volumes:
- /Users/zgh/Docker/RedisCluster_3M3S/RedisConf/redis.conf:/etc/redis/redis.conf
networks:
# 使用名为redis_cluster_3m3s_net的网络并设置容器IP
redis_cluster_3m3s_net:
ipv4_address: 120.120.120.14

Redis-Service-5:
image: redis:7.0
container_name: node-5
command: [ "redis-server", "/etc/redis/redis.conf" ]
ports:
- "6375:6379"
- "16375:16379"
volumes:
- /Users/zgh/Docker/RedisCluster_3M3S/RedisConf/redis.conf:/etc/redis/redis.conf
networks:
# 使用名为redis_cluster_3m3s_net的网络并设置容器IP
redis_cluster_3m3s_net:
ipv4_address: 120.120.120.15

Redis-Service-6:
image: redis:7.0
container_name: node-6
command: [ "redis-server", "/etc/redis/redis.conf" ]
ports:
- "6376:6379"
- "16376:16379"
volumes:
- /Users/zgh/Docker/RedisCluster_3M3S/RedisConf/redis.conf:/etc/redis/redis.conf
networks:
# 使用名为redis_cluster_3m3s_net的网络并设置容器IP
redis_cluster_3m3s_net:
ipv4_address: 120.120.120.16

# 定义网络
networks:
# 定义一个名为redis_cluster_3m3s_net的网络
redis_cluster_3m3s_net:
ipam:
config:
# 设置网段
- subnet: 120.120.120.0/24

Redis指定版本的配置文件redis.conf可通过下述链接下载对应版本的安装包后解压后获取

1
http://download.redis.io/releases/

修改Redis配置文件redis.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
...

# 注释bind配置项
# bind 127.0.0.1 -::1

# 设为 no, 关闭保护模式
protected-mode no

# 端口设为6379
port 6379

# 设为no, 因为docker启动时会通过-d参数来让其实现后台运行
daemonize no

# 修改数据库数量, 用于验证配置文件是否生效
databases 5

# 设置访问主库时的密码
masterauth "52996"

# 设置Redis密码
requirepass 52996

# 使能集群模式
cluster-enabled yes

# 集群是否要求槽全覆盖
# yes:当负责某个槽的主库下线且没有相应的从库进行故障恢复时,集群整体不可用。即其他槽的节点在线也无法访问
# no:当负责某个槽的主库下线且没有相应的从库进行故障恢复时,集群仍然可用。即可访问其他槽的数据
cluster-require-full-coverage yes

...

这里对于集群中的6个节点,均使用上述同一个配置文件。目录结构如下所示

figure 1.jpg

现在,进行docker-compose.yml文件所在目录,利用Docker Compose命令创建容器

1
docker-compose up -d

figure 2.jpg

执行下述命令组建集群

1
2
3
4
5
6
docker exec -it node-1 \
redis-cli -p 6379 -a 52996 --cluster create \
120.120.120.11:6379 120.120.120.12:6379 \
120.120.120.13:6379 120.120.120.14:6379 \
120.120.120.15:6379 120.120.120.16:6379 \
--cluster-replicas 1

命令执行过程中,当分配好每个节点的槽范围后,需要输入yes进行确认,以便完成集群构建。其中,这里node 1、node 2、node 3节点为Master节点

至此这个3主3从的Redis集群就已经搭建完毕了,我们向其中添加一些数据

figure 3.jpg

可通过下述命令查看集群信息

1
2
3
4
5
# 查看各Master下的槽位数量、Key数量、Slave数量等统计信息
redis-cli -c -p 6379 -a 52996 --cluster info 120.120.120.14:6379

# redis 命令:查看集群节点的详细信息
cluster nodes

figure 4.jpg

扩容

准备新节点

先期望对上述的3主3从的Redis集群进行扩容,首先Docker Compose准备3个新Redis节点——node 7、node 8、node 9。docker-compose.yml文件如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# Redis Cluster 扩容节点

# Compose 版本
version: '3.8'

# 定义服务
services:

Redis-Service-7:
image: redis:7.0
container_name: node-7
command: [ "redis-server", "/etc/redis/redis.conf" ]
ports:
- "6377:6379"
- "16377:16379"
volumes:
- /Users/zgh/Docker/RedisCluster_3M3S/RedisConf/redis.conf:/etc/redis/redis.conf
networks:
# 使用名为 redis-cluster-3m3s_redis_cluster_3m3s_net 的网络并设置容器IP
redis-cluster-3m3s_redis_cluster_3m3s_net:
ipv4_address: 120.120.120.17

Redis-Service-8:
image: redis:7.0
container_name: node-8
command: [ "redis-server", "/etc/redis/redis.conf" ]
ports:
- "6378:6379"
- "16378:16379"
volumes:
- /Users/zgh/Docker/RedisCluster_3M3S/RedisConf/redis.conf:/etc/redis/redis.conf
networks:
# 使用名为 redis-cluster-3m3s_redis_cluster_3m3s_net 的网络并设置容器IP
redis-cluster-3m3s_redis_cluster_3m3s_net:
ipv4_address: 120.120.120.18

Redis-Service-9:
image: redis:7.0
container_name: node-9
command: [ "redis-server", "/etc/redis/redis.conf" ]
ports:
- "6379:6379"
- "16379:16379"
volumes:
- /Users/zgh/Docker/RedisCluster_3M3S/RedisConf/redis.conf:/etc/redis/redis.conf
networks:
# 使用名为 redis-cluster-3m3s_redis_cluster_3m3s_net 的网络并设置容器IP
redis-cluster-3m3s_redis_cluster_3m3s_net:
ipv4_address: 120.120.120.19

# 使用外部已存在的名为 redis-cluster-3m3s_redis_cluster_3m3s_net 的网络
networks:
redis-cluster-3m3s_redis_cluster_3m3s_net:
external: true

由于需要保证3个新节点与原Redis集群在同一个网络下,可通过下述命令查看原集群所使用的完整网络名

1
2
# 查看Docker的网络列表
docker network ls

figure 5.jpg

这里对于这3个新的Redis节点,也使用上述集群的配置文件。目录结构如下所示

figure 6.jpg

现在,进行新节点对应的docker-compose.yml文件所在目录,利用Docker Compose命令创建新节点容器

1
docker-compose up -d

figure 7.jpg

将新节点node 7添加集群当中并作为Master节点

这里我们通过cluster meet命令将新节点node 7添加到集群当中

1
2
# 将指定节点加入当前集群中
redis-cli -c -p 6379 -a 52996 cluster meet 120.120.120.17 6379

通过集群中节点数cluster_known_nodes值从6变为7可以看出,新节点node 7加入集群成功。虽然该新节点的角色是Master节点,但由于未分配任何槽给该节点,故cluster_size值依然为3

figure 8.jpg

这里,我们期望将node 7节点作为集群中的Master节点,故利用 —cluster reshard 重分配命令实现将集群中其他Master节点的槽分配给它

1
2
# 对Redis集群中的槽进行重分配,命令中只需指定 集群中任意一个已知节点的地址信息即可
redis-cli -c -p 6379 -a 52996 --cluster reshard 120.120.120.14:6379

执行该命令后,会启动一个交互命令行,询问重分配操作的细节。我们需要依次输入下列信息

  • 输入迁出槽位的总数。这里我们输入1000
  • 输入接收槽位的节点ID。这里我们输入node 7节点的节点ID
  • 确认哪些节点需要迁出槽位。这里有两种方式:依次指定需要迁出槽位的节点ID(显然需要为Master节点),最后输入done表示指定完毕;直接输入all表示从所有Mater节点中进行迁出

figure 9.jpg

这里的重分配目标就是从node 1、node 3节点中将总计1000个槽位分配给node 7节点。然后其会生成相应的重分配计划,并询问是否执行。这里输入 yes 后,将会真正地执行槽迁移

figure 10.jpg

从下图不难看出,node 7节点现在被分配了1000个槽位,同时node 1、node 3节点的槽位均比重分配前少了500个槽位。进一步,由于node 7节点现在已经被分配了槽,故cluster_size值由3变为4了

figure 11.jpg

添加从节点到集群中

将新节点node 8作为node 7节点的从节点

现在我们将node 8节点添加集群当中。之前我们使用cluster meet命令添加节点到集群中,其实也可以使用 —cluster add-node 命令实现将新节点添加到集群当中

1
2
3
# 将120.120.120.18:6379新节点 加入到 120.120.120.14:6379节点所在的集群当中
# 命令中的120.120.120.14:6379可以替换为集群中任意一个已知节点的地址信息
redis-cli -c -p 6379 -a 52996 --cluster add-node 120.120.120.18:6379 120.120.120.14:6379

从集群中已知节点数cluster_known_nodes从7变为8。可以看出,node 8成功加入集群且是一个Master角色

figure 12.jpg

此时,我们需要将node 8设置为node 7节点的从节点

1
2
3
# 该命令实现将当前节点设置为指定节点(这里即为node 7节点)的从节点
# 这里当前节点为node 8节点。故,我们需要在node 8节点容器中执行该命令
docker exec -it node-8 redis-cli -c -p 6379 -a 52996 cluster replicate <node 7节点的节点ID>

figure 13.jpg

将新节点node 9作为node 7节点的从节点

上文当中,我们将新节点node 8作为node 7节点的从节点。实际上是分为两步完成的。先将node 8节点加入集群、再将node 8节点设置为node 7的从节点。事实上,这两个步骤可以通过一条命令直接实现。这里我们将新节点node 9作为node 7节点的从节点

1
2
3
4
5
# 实现新从节点加入集群,同时将该新从节点 设置为指定主节点的从节点
docker exec -it node-1 redis-cli -c -p 6379 -a 52996 --cluster add-node <新从节点IP>:<新从节点Port> <集群任意已知节点的IP>:<集群任意已知节点的Port> --cluster-slave --cluster-master-id <主节点的节点ID>

# 实现新节点node 9加入集群,同时将node 9节点设置为node 7节点的从节点
docker exec -it node-1 redis-cli -c -p 6379 -a 52996 --cluster add-node 120.120.120.19:6379 120.120.120.14:6379 --cluster-slave --cluster-master-id <node 7节点的节点ID>

命令执行过程,如下所示

figure 14.jpg

结果如下所示,可以看到,现在node 7节点下有2个从节点——node 8、node 9

figure 15.jpg

缩容

从集群中移除从节点

至此,该集群是一个4主5从的集群了。其中,node 7节点有两个从节点。现在我们期望将主节点node 7及其对应的所有从节点全部从集群中移除。将集群恢复为先前的3主3从架构。即所谓的缩容。这里我们先下线从节点——node 8、node 9,再下线主节点node 7。以避免主从间不必要的数据复制同步,下文会有对此问题的详细说明

1
2
3
4
5
6
7
8
# 从集群中移除指定节点
docker exec -it node-1 redis-cli -c -p 6379 -a 52996 --cluster del-node <节点IP>:<节点Port> <节点ID>

# 从集群中移除node 8节点
docker exec -it node-1 redis-cli -c -p 6379 -a 52996 --cluster del-node 120.120.120.18:6379 <node 8节点 的节点ID>

# 从集群中移除node 9节点
docker exec -it node-1 redis-cli -c -p 6379 -a 52996 --cluster del-node 120.120.120.19:6379 <node 9节点 的节点ID>

不难看出,此时,集群中不再有node 8、node 9节点。同时,node 7节点下无从节点

figure 16.jpg

从集群中移除主节点

首先需要将node 7节点分配的槽位全部迁移到集群中其他节点中

figure 17.jpg

故需再次使用 —cluster reshard 重分配命令

1
2
# 对Redis集群中的槽进行重分配,命令中只需指定 集群中任意一个已知节点的地址信息即可
redis-cli -c -p 6379 -a 52996 --cluster reshard 120.120.120.14:6379

这里我们将node 7节点的槽全部迁移到node 2节点当中。在输入迁出槽的总数时,直接输入最大值即可

figure 18.jpg

然后对于重分配计划输入 yes 执行槽迁移。通过下图不难看出,重分配后,node 2节点中槽位多了1000个。同时,node 7节点也变为node 2节点的从节点了。事实上,如果我们此前未先将node 7节点下的从节点node 8、node 9从集群当中移除的话,node 8、node 9节点也将会成为node 2节点的从节点。由于最终node 8、node 9节点也需要下线,故这将会导致主从间(node 2 - node 8、node 2 - node 9)不必要的数据复制同步

figure 19.jpg

现在,只需继续将node 7节点从集群中移除即可

1
2
# 从集群中移除node 7节点
redis-cli -c -p 6379 -a 52996 --cluster del-node 120.120.120.17:6379 <node 7节点 的节点ID>

figure 20.jpg

Note

在集群扩容、缩容后,各节点的槽位数量不均衡时,可利用 —cluster rebalance 命令进行重新平衡

1
2
# 命令中的120.120.120.14:6379可以替换为集群中任意一个已知节点的地址信息
redis-cli -c -p 6379 -a 52996 --cluster rebalance 120.120.120.14:6379

figure 21.jpg

请我喝杯咖啡捏~

欢迎关注我的微信公众号:青灯抽丝