Redis 集群

发布于:2025-02-27 ⋅ 阅读:(13) ⋅ 点赞:(0)

基本概念

使用 Redis 存储数据时,如果要存储的数据量很⼤, 接近超出了 master / slave 所在机器的物理内存, 就很可能会出现严重问题,这时我们 如何获取更⼤的空间? 加机器即可! 所谓 "⼤数据" 的核⼼, 其实就是⼀台机器搞不定了, ⽤多台机器来搞。
Redis 的集群就是在上述的思路之下, 引⼊多组 Master / Slave , 每⼀组 Master / Slave 存储数据全集的⼀部分, 从⽽构成⼀个更⼤的整体, 称为 Redis 集群 (Cluster)。
假定整个数据全集是 1 TB, 引⼊三组 Master / Slave 来存储. 那么每⼀组机器只需要存储整个数据全集的 1/3 即可。
在上述图中,
  • Master1 和 Slave11 和 Slave12 保存的是同样的数据. 占总数据的 1/3
  • Master2 和 Slave21 和 Slave22 保存的是同样的数据. 占总数据的 1/3
  • Master3 和 Slave31 和 Slave32 保存的是同样的数据. 占总数据的 1/3
每个 Slave 都是对应 Master 的备份(当 Master 挂了, 对应的 Slave 会补位成 Master);每个红框部分都可以称为是⼀个分⽚ (Sharding);如果全量数据进⼀步增加, 只要再增加更多的分⽚, 即可解决。

数据分片算法

Redis cluster 的核⼼思路是⽤多组机器来存数据的每个部分. 那么接下来的核⼼问题就是, 给定⼀个数据 (⼀个具体的 key), 那么这个数据应该存储在哪个分⽚上? 读取的时候⼜应该去哪个分⽚读取?围绕这个问题, 业界有三种⽐较主流的实现⽅式.

哈希求余

设有 N 个分⽚,使⽤ [0, N-1] 这样序号进⾏编号,针对某个给定的 key先计算 hash 值再把得到的结果 % N得到的结果即为分⽚编号。
例如, N 为 3. 给定 key 为 hello, 对 hello 计算 hash 值(⽐如使⽤ md5 算法), 得到的结果为bc4b2a76b9719d91 , 再把这个结果 % 3, 结果为 0, 那么就把 hello 这个 key 放到 0 号分⽚上.
后续如果要取某个 key 的记录, 也是针对 key 计算 hash , 再对 N 求余, 就可以找到对应的分⽚编号了.
  • 优点: 简单⾼效, 数据分配均匀.
  • 缺点: ⼀旦需要进⾏扩容, N 改变了, 原有的映射规则被破坏, 就需要让节点之间的数据相互传输, 重新排列, 以满⾜新的映射规则. 此时需要搬运的数据量是⽐较多的, 开销较⼤.
例如,N 为 3 的时候, [100, 120] 这 21 个 hash 值的分布如下图所示;当引⼊⼀个新的分⽚, N 从 3 => 4 时, ⼤量的 key 都需要重新映射(某个key % 3 和 % 4 的结果不⼀样, 就映射到不同机器上了).

⼀致性哈希算法

为了降低上述的搬运开销, 能够更⾼效扩容, 业界提出了 "⼀致性哈希算法"。key 映射到分⽚序号的过程不再是简单求余了, ⽽是改成以下过程:
第⼀步, 把 0 -> 2^32-1 这个数据空间, 映射到⼀个圆环上. 数据按照顺时针⽅向增⻓.
第⼆步, 假设当前存在三个分⽚, 就把分⽚放到圆环的某个位置上.
第三步, 假定有⼀个 key, 计算得到 hash 值 H, 那么这个 key 映射到哪个分⽚呢? 规则很简单, 就是从 H 所在位置, 顺时针往下找, 找到的第⼀个分⽚, 即为该 key 所从属的分⽚.
这就相当于, N 个分⽚的位置, 把整个圆环分成了 N 个管辖区间. Key 的 hash 值落在某个区间内, 就归对应区间管理.
在这个情况下, 如果扩容⼀个分⽚, 如何处理呢?
原有分⽚在环上的位置不动, 只要在环上新安排⼀个分⽚位置即可。例如把 0 号分⽚上的部分数据, 搬运给 3 号分⽚,1 号分⽚和 2 号分⽚管理的区间都是不变的.
  • 优点: ⼤⼤降低了扩容时数据搬运的规模, 提⾼了扩容操作的效率.
  • 缺点: 数据分配不均匀 (有的多有的少, 数据倾斜)

哈希槽分区算法 (Redis 使用)

为了解决上述问题 (搬运成本⾼ 和 数据分配不均匀), Redis cluster 引⼊了哈希槽 (hash slots) 算法.
hash_slot = crc16(key) % 16384 //crc16为一种hash算法
相当于是把整个哈希值, 映射到 16384 个槽位上, 也就是 [0, 16383],然后再把这些槽位⽐较均匀的分配给每个分⽚. 每个分⽚的节点都需要记录⾃⼰持有哪些分⽚,可以使用位图结构。
假设当前有三个分⽚, ⼀种可能的分配⽅式:
  • 0 号分⽚: [0, 5461], 共 5462 个槽位
  • 1 号分⽚: [5462, 10923], 共 5462 个槽位
  • 2 号分⽚: [10924, 16383], 共 5460 个槽位
为什么是 16384 个槽位?
  • 节点之间通过⼼跳包通信. ⼼跳包中包含了该节点持有哪些 slots. 这个是使⽤位图这样的数据结构表⽰的. 表⽰ 16384 (16k) 个 slots, 需要的位图⼤⼩是 2KB. 如果给定的 slots 数更多了, ⽐如 65536 个了, 此时就需要消耗更多的空间, 8 KB 位图表⽰了. 8 KB, 对于内存来说不算什么, 但是在频繁的⽹络⼼跳包中, 还是⼀个不⼩的开销的.
  • 另⼀⽅⾯, Redis 集群⼀般不建议超过 1000 个分⽚. 所以 16k 对于最⼤ 1000 个分⽚来说是⾜够⽤的, 同时也会使对应的槽位配置位图体积不⾄于很⼤.

集群搭建 (基于 docker)

接下来基于 docker, 搭建⼀个集群. 每个节点都是⼀个容器. 拓扑结构如下(主从节点并不一定如下表示,为随机的):

第⼀步: 创建目录和配置

创建 redis-cluster ⽬录. 内部创建两个⽂件,docker-compose.yml 是 Docker Compose 的配置文件,用于定义和管理多容器的 Docker 应用,generate.sh 是一个 Shell 脚本文件,通常用于生成某些内容或执行一系列自动化任务。
redis-cluster/
├── docker-compose.yml
└── generate.sh
generate.sh 内容如下,目的是创建 11 个 redis 节点:
for port in $(seq 1 9); \
do \
mkdir -p redis${port}/
touch redis${port}/redis.conf
cat << EOF > redis${port}/redis.conf
port 6379
bind 0.0.0.0
protected-mode no
appendonly yes
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 172.30.0.10${port}
cluster-announce-port 6379
cluster-announce-bus-port 16379
EOF
done
# 注意 cluster-announce-ip 的值有变化,该值为 docker 容器模拟的主机ip
for port in $(seq 10 11); \
do \
mkdir -p redis${port}/
touch redis${port}/redis.conf
cat << EOF > redis${port}/redis.conf
port 6379
bind 0.0.0.0
protected-mode no
appendonly yes
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 172.30.0.1${port}
cluster-announce-port 6379
cluster-announce-bus-port 16379
EOF
done
执⾏命令
bash generate.sh
⽣成⽬录如下:
redis-cluster/
├── docker-compose.yml
├── generate.sh
├── redis1
│   └── redis.conf
├── redis10
│   └── redis.conf
├── redis11
│   └── redis.conf
├── redis2
│   └── redis.conf
├── redis3
│   └── redis.conf
├── redis4
│   └── redis.conf
├── redis5
│   └── redis.conf
├── redis6
│   └── redis.conf
├── redis7
│   └── redis.conf
├── redis8
│   └── redis.conf
└── redis9
    └── redis.conf
其中 redis.conf 每个都不同. 以 redis1 为例:
区别在于每个配置中配置的 cluster-announce-ip 是不同的, 其他部分都相同.
port 6379
bind 0.0.0.0
protected-mode no
appendonly yes
cluster-enabled yes #开启集群
cluster-config-file nodes.conf #集群节点⽣成的配置
cluster-node-timeout 5000 #节点失联的超时时间
cluster-announce-ip 172.30.0.101 #节点⾃⾝ ip
cluster-announce-port 6379 #节点⾃⾝的业务端口,客户端连接的端口
cluster-announce-bus-port 16379 #节点⾃⾝的总线端口,集群管理的信息交互是通过这个端⼝进⾏的.

第⼆步: 编写 docker-compose.yml

  • 先创建 networks, 并分配⽹段为 172.30.0.0/24
  • 配置每个节点. 注意配置⽂件映射, 端⼝映射, 以及容器的 ip 地址. 设定成固定 ip ⽅便后续的观察和操作.
此处的端⼝映射不配置也可以, 配置的⽬的是为了可以通过宿主机 ip + 映射的端⼝进⾏访问. 通过 容器⾃⾝ ip:6379 的⽅式也可以访问.
version: '3.7'
networks:
 mynet:
 ipam:
 config:
 - subnet: 172.30.0.0/24 #创建子网
services:
 redis1:
 image: 'redis:5.0.9'
 container_name: redis1
 restart: always
 volumes:
 - ./redis1/:/etc/redis/
 ports:
 - 6371:6379 #端口映射,方便在容器外通过客户端直接访问
 - 16371:16379
 command:
 redis-server /etc/redis/redis.conf
 networks:
 mynet:
 ipv4_address: 172.30.0.101 #配置静态ip,注意网络号与子网一致
 redis2:
 image: 'redis:5.0.9'
 container_name: redis2
 restart: always
volumes:
 - ./redis2/:/etc/redis/
 ports:
 - 6372:6379
 - 16372:16379
 command:
 redis-server /etc/redis/redis.conf
 networks:
 mynet:
 ipv4_address: 172.30.0.102
 redis3:
 image: 'redis:5.0.9'
 container_name: redis3
 restart: always
 volumes:
 - ./redis3/:/etc/redis/
 ports:
 - 6373:6379
 - 16373:16379
 command:
 redis-server /etc/redis/redis.conf
 networks:
 mynet:
 ipv4_address: 172.30.0.103
 redis4:
 image: 'redis:5.0.9'
 container_name: redis4
 restart: always
 volumes:
 - ./redis4/:/etc/redis/
 ports:
 - 6374:6379
 - 16374:16379
 command:
 redis-server /etc/redis/redis.conf
 networks:
 mynet:
 ipv4_address: 172.30.0.104
 redis5:
 image: 'redis:5.0.9'
 container_name: redis5
 restart: always
 volumes:
 - ./redis5/:/etc/redis/
ports:
 - 6375:6379
 - 16375:16379
 command:
 redis-server /etc/redis/redis.conf
 networks:
 mynet:
 ipv4_address: 172.30.0.105
 redis6:
 image: 'redis:5.0.9'
 container_name: redis6
 restart: always
 volumes:
 - ./redis6/:/etc/redis/
 ports:
 - 6376:6379
 - 16376:16379
 command:
 redis-server /etc/redis/redis.conf
 networks:
 mynet:
 ipv4_address: 172.30.0.106
 redis7:
 image: 'redis:5.0.9'
 container_name: redis7
 restart: always
 volumes:
 - ./redis7/:/etc/redis/
 ports:
 - 6377:6379
 - 16377:16379
 command:
 redis-server /etc/redis/redis.conf
 networks:
 mynet:
 ipv4_address: 172.30.0.107
 redis8:
 image: 'redis:5.0.9'
 container_name: redis8
 restart: always
 volumes:
 - ./redis8/:/etc/redis/
 ports:
 - 6378:6379
- 16378:16379
 command:
 redis-server /etc/redis/redis.conf
 networks:
 mynet:
 ipv4_address: 172.30.0.108
 redis9:
 image: 'redis:5.0.9'
 container_name: redis9
 restart: always
 volumes:
 - ./redis9/:/etc/redis/
 ports:
 - 6379:6379
 - 16379:16379
 command:
 redis-server /etc/redis/redis.conf
 networks:
 mynet:
 ipv4_address: 172.30.0.109
 
 redis10:
 image: 'redis:5.0.9'
 container_name: redis10
 restart: always
 volumes:
 - ./redis10/:/etc/redis/
 ports:
 - 6380:6379
 - 16380:16379
 command:
 redis-server /etc/redis/redis.conf
 networks:
 mynet:
 ipv4_address: 172.30.0.110
 redis11:
 image: 'redis:5.0.9'
 container_name: redis11
 restart: always
 volumes:
 - ./redis11/:/etc/redis/
 ports:
 - 6381:6379
 - 16381:16379
 command:
redis-server /etc/redis/redis.conf
 networks:
 mynet:
 ipv4_address: 172.30.0.111

第三步: 启动容器

在启动容器之前,需要把之前运行的 redis 服务都关闭,避免因为端口冲突等原因导致启动容器失败,可以通过以下指令查看有哪些 redis 服务还在运行,而后通过 kill 命令关闭

ps ajx | grep redis

启动容器

docker-compose up -d

第四步: 构建集群

使用 redis-cli 创建集群,创建的节点并不知道谁是主节点,谁是从节点,为随机分配的:

redis-cli --cluster create 172.30.0.101:6379 172.30.0.102:6379 
172.30.0.103:6379 172.30.0.104:6379 172.30.0.105:6379 172.30.0.106:6379 
172.30.0.107:6379 172.30.0.108:6379 172.30.0.109:6379 --cluster-replicas 2
  • --cluster create:表⽰建⽴集群. 后⾯填写每个节点的 ip 和地址.
  • --cluster-replicas:后面填写数字,表示每个主节点的从节点数量.

执⾏之后, 容器之间会进⾏加⼊集群操作,而后打印出日志,记录主节点分配到的槽位,哪些是主节点,哪些是从节点

>>> Performing hash slots allocation on 9 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 172.30.0.105:6379 to 172.30.0.101:6379
Adding replica 172.30.0.106:6379 to 172.30.0.101:6379
Adding replica 172.30.0.107:6379 to 172.30.0.102:6379
Adding replica 172.30.0.108:6379 to 172.30.0.102:6379
Adding replica 172.30.0.109:6379 to 172.30.0.103:6379
Adding replica 172.30.0.104:6379 to 172.30.0.103:6379
M: e4f37f8f0ea0dafc584349999795716613910e51 172.30.0.101:6379
 slots:[0-5460] (5461 slots) master
M: 5f71983ad52cc7077ce8874ae1c4f9c23d9f502c 172.30.0.102:6379
 slots:[5461-10922] (5462 slots) master
M: b3c0a96f6a206088ecea639147b6fcf903afe872 172.30.0.103:6379
 slots:[10923-16383] (5461 slots) master
S: 85025819223f12615046c54d89f510e9cd0444a1 172.30.0.104:6379
 replicates b3c0a96f6a206088ecea639147b6fcf903afe872
S: 2e5dc211288784ba55d554a377b87bfe2b5398db 172.30.0.105:6379
 replicates e4f37f8f0ea0dafc584349999795716613910e51
S: 29f05d98982bd3df05d0222091e4b8ef9569f424 172.30.0.106:6379
 replicates e4f37f8f0ea0dafc584349999795716613910e51
S: 3584840ac704c3ee016f3bdcca3f7ebe6f6e8e80 172.30.0.107:6379
 replicates 5f71983ad52cc7077ce8874ae1c4f9c23d9f502c
S: 0a889103b35db2a6e82e8c09904bbef310cff3b1 172.30.0.108:6379
 replicates 5f71983ad52cc7077ce8874ae1c4f9c23d9f502c
S: 00ba82bed6abeb015116d51d1af7fcb1609d03ad 172.30.0.109:6379
 replicates b3c0a96f6a206088ecea639147b6fcf903afe872
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join
...
>>> Performing Cluster Check (using node 172.30.0.101:6379)
M: e4f37f8f0ea0dafc584349999795716613910e51 172.30.0.101:6379
 slots:[0-5460] (5461 slots) master
 2 additional replica(s)
M: 5f71983ad52cc7077ce8874ae1c4f9c23d9f502c 172.30.0.102:6379
 slots:[5461-10922] (5462 slots) master
 2 additional replica(s)
S: 2e5dc211288784ba55d554a377b87bfe2b5398db 172.30.0.105:6379
 slots: (0 slots) slave
 replicates e4f37f8f0ea0dafc584349999795716613910e51
S: 0a889103b35db2a6e82e8c09904bbef310cff3b1 172.30.0.108:6379
 slots: (0 slots) slave
 replicates 5f71983ad52cc7077ce8874ae1c4f9c23d9f502c
S: 3584840ac704c3ee016f3bdcca3f7ebe6f6e8e80 172.30.0.107:6379
 slots: (0 slots) slave
 replicates 5f71983ad52cc7077ce8874ae1c4f9c23d9f502c
S: 85025819223f12615046c54d89f510e9cd0444a1 172.30.0.104:6379
 slots: (0 slots) slave
 replicates b3c0a96f6a206088ecea639147b6fcf903afe872
S: 00ba82bed6abeb015116d51d1af7fcb1609d03ad 172.30.0.109:6379
 slots: (0 slots) slave
replicates b3c0a96f6a206088ecea639147b6fcf903afe872
S: 29f05d98982bd3df05d0222091e4b8ef9569f424 172.30.0.106:6379
 slots: (0 slots) slave
 replicates e4f37f8f0ea0dafc584349999795716613910e51
M: b3c0a96f6a206088ecea639147b6fcf903afe872 172.30.0.103:6379
 slots:[10923-16383] (5461 slots) master
 2 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
此时, 使⽤客⼾端连上集群中的任何⼀个节点, 都相当于连上了整个集群.
  • 客⼾端后⾯要加上 -c 选项, 否则如果 key 没有落到当前节点上, 是不能操作的. -c 会⾃动把请求重定向到对应节点.
redis-cli -h 172.30.0.101 -p 6379 -c
  • 使⽤ cluster nodes 可以查看到整个集群的情况

主节点宕机

⼿动停⽌⼀个 master 节点, 观察效果。 ⽐如上述拓扑结构中, 可以看到 redis1 redis2 redis3 是主节点, 随便挑⼀个停掉
docker stop redis1

连上 redis2 , 观察结果

redis-cli -h 172.30.0.102 -p 6379 -c
172.30.0.102:6379> cluster nodes
e4f37f8f0ea0dafc584349999795716613910e51 172.30.0.101:6379@16379 master,fail -1682599172083 1682599170000 1 connected
0a889103b35db2a6e82e8c09904bbef310cff3b1 172.30.0.108:6379@16379 slave 5f71983ad52cc7077ce8874ae1c4f9c23d9f502c 0 1682603536508 8 connected
29f05d98982bd3df05d0222091e4b8ef9569f424 172.30.0.106:6379@16379 slave 2e5dc211288784ba55d554a377b87bfe2b5398db 0 1682603537512 10 connected
00ba82bed6abeb015116d51d1af7fcb1609d03ad 172.30.0.109:6379@16379 slave b3c0a96f6a206088ecea639147b6fcf903afe872 0 1682603536000 9 connected
5f71983ad52cc7077ce8874ae1c4f9c23d9f502c 172.30.0.102:6379@16379 myself,master - 0 1682603535000 2 connected 5461-10922
b3c0a96f6a206088ecea639147b6fcf903afe872 172.30.0.103:6379@16379 master - 0 1682603537009 3 connected 10923-16383
2e5dc211288784ba55d554a377b87bfe2b5398db 172.30.0.105:6379@16379 master - 0 1682603537000 10 connected 0-5460
3584840ac704c3ee016f3bdcca3f7ebe6f6e8e80 172.30.0.107:6379@16379 slave 5f71983ad52cc7077ce8874ae1c4f9c23d9f502c 0 1682603537512 7 connected
85025819223f12615046c54d89f510e9cd0444a1 172.30.0.104:6379@16379 slave b3c0a96f6a206088ecea639147b6fcf903afe872 0 1682603536708 4 connected
可以看到, 172.30.0.101 已经提⽰ fail, 然后 原本是 slave 的 172.30.0.105 成了新的 master.
如果重新启动 redis1,172.30.0.101 就会变成 slave
docker start redis1
如果想要把 172.30.0.101 重新设定成 master,需要先登录到 172.30.0.101 上,而后执⾏ cluster failover 进⾏集群恢复。

处理流程

  • 故障判定
集群中的所有节点, 都会周期性的使⽤⼼跳包进⾏通信.
  1. 节点 A 给 节点 B 发送 ping 包, B 就会给 A 返回⼀个 pong 包. ping 和 pong 除了 message type 属性之外, 其他部分都是⼀样的. 这⾥包含了集群的配置信息(该节点的id, 该节点从属于哪个分⽚, 是主节点还是从节点, 从属于谁, 持有哪些 slots 的位图...).
  2. 每个节点, 每秒钟, 都会给⼀些随机的节点发起 ping 包, ⽽不是全发⼀遍. 这样设定是为了避免在节点很多的时候, ⼼跳包也⾮常多
  3. 当节点 A 给节点 B 发起 ping 包, B 不能如期回应的时候, 此时 A 就会尝试重置和 B 的 tcp 连接, 看能否连接成功. 如果仍然连接失败, A 就会把 B 设为 PFAIL 状态(相当于主观下线).
  4. A 判定 B 为 PFAIL 之后, 会通过 redis 内置的 Gossip 协议, 和其他节点进⾏沟通, 向其他节点确认 B 的状态. (每个节点都会维护⼀个⾃⼰的 "下线列表", 由于视⻆不同, 每个节点的下线列表也不⼀定相同).
  5. 此时 A 发现其他很多节点, 也认为 B 为 PFAIL, 并且数⽬超过总集群个数的⼀半, 那么 A 就会把 B 标记成 FAIL (相当于客观下线), 并且把这个消息同步给其他节点(其他节点收到之后, 也会把 B 标记成 FAIL). ⾄此, B 就彻底被判定为故障节点了.
  • 故障迁移
上述例⼦中, B 故障, 并且 A 把 B FAIL 的消息告知集群中的其他节点。如果 B 是从节点, 那么不需要进⾏故障迁移;如果 B 是主节点, 那么就会由 B 的从节点 (⽐如 C 和 D) 触发故障迁移了。所谓故障迁移, 就是指把从节点提拔成主节点, 继续给整个 redis 集群提供⽀持。
具体流程如下:
  1. 从节点判定⾃⼰是否具有参选资格. 如果从节点和主节点已经太久没通信(此时认为从节点的数据和主节点差异太⼤了), 时间超过阈值, 就失去竞选资格.
  2. 具有资格的节点, ⽐如 C 和 D, 就会先休眠⼀定时间. 休眠时间 = 500ms 基础时间 + [0, 500ms] 随机时间 + 排名 * 1000ms. offset 的值越⼤, 则排名越靠前(越⼩).
  3. ⽐如 C 的休眠时间到了, C 就会给其他所有集群中的节点, 进⾏拉票操作. 但是只有主节点才有投票资格.
  4. 主节点就会把⾃⼰的票投给 C (每个主节点只有 1 票). 当 C 收到的票数超过主节点数⽬的⼀半, C 就会晋升成主节点. (C ⾃⼰负责执⾏ slaveof no one, 并且让 D 执⾏ slaveof C).
  5. 同时, C 还会把⾃⼰成为主节点的消息, 同步给其他集群的节点. ⼤家也都会更新⾃⼰保存的集群结构信息.

集群扩容

第⼀步: 把新的主节点加入到集群

上⾯已经把 redis1 - redis9 重新构成了集群. 接下来把 redis10 和 redis11 也加⼊集群. 此处我们把 redis10 作为主机, redis11 作为从机.
redis-cli --cluster add-node 172.30.0.110:6379 172.30.0.101:6379
  • add-node 后的第⼀组地址是新节点的地址. 第⼆组地址是集群中的任意节点地址.
此时的集群状态如下, 可以看到 172.30.0.110 这个节点已经成为了集群中的主节点
127.0.0.1:6379> cluster nodes
b3f2ba758318f4bd54031c98c01d7a6155ff43d3 172.30.0.102:6379@16379 master - 0 1683183720184 2 connected 5461-10922
e34911c57d7605903de84ec05b3deac611aaef7e 172.30.0.105:6379@16379 slave 00d319e23ef76a4d51e74600c42ee2a371ae81f6 0 1683183722189 5 connected
522a1bd88a1a9084e6919fa88f4bf1c3655ad837 172.30.0.110:6379@16379 master - 0 1683183720000 10 connected
579282abe81b3f20ffd17d5a1956cdca3b0e71b0 172.30.0.103:6379@16379 master - 0 1683183721084 3 connected 10923-16383
00d319e23ef76a4d51e74600c42ee2a371ae81f6 172.30.0.101:6379@16379 master - 0 1683183721185 1 connected 0-5460
6cf48cc11d0171b6ab1b418808473167acd7986e 172.30.0.106:6379@16379 slave 00d319e23ef76a4d51e74600c42ee2a371ae81f6 0 1683183720000 6 connected
e9ea79b1326ea5a75a1701d5c12a0f6081c1d043 172.30.0.109:6379@16379 myself,slave 579282abe81b3f20ffd17d5a1956cdca3b0e71b0 0 1683183720000 9 connected
fd18c7f164b09ec563f4573ec9d6466e6769221e 172.30.0.108:6379@16379 slave b3f2ba758318f4bd54031c98c01d7a6155ff43d3 0 1683183720684 8 connected
2a248acb47f0036655397897f9800c70ea22514f 172.30.0.104:6379@16379 slave 579282abe81b3f20ffd17d5a1956cdca3b0e71b0 0 1683183722088 4 connected
628d1ec9ceef6760b9038c4fbc83ee92430062ac 172.30.0.107:6379@16379 slave b3f2ba758318f4bd54031c98c01d7a6155ff43d3 0 1683183720000 7 connected

第⼆步: 重新分配 slots

redis-cli --cluster reshard 172.30.0.101:6379
  • reshard 后的地址是集群中的任意节点地址.
执⾏之后, 会进⼊交互式操作, redis 会提⽰⽤⼾输⼊以下内容:
  • 多少个 slots 要进⾏ reshard ? (此处我们填写 4096)
  • 哪个节点来接收这些 slots ? (此处我们填写 172.30.0.110 这个节点的集群节点 id)
  • 这些 slots 从哪些节点搬运过来? (此处我们填写 all, 表⽰从其他所有的节点都进⾏搬运)
How many slots do you want to move (from 1 to 16384)? 4096
What is the receiving node ID? 522a1bd88a1a9084e6919fa88f4bf1c3655ad837
Please enter all the source node IDs.
 Type 'all' to use all the nodes as source nodes for the hash slots.
 Type 'done' once you entered all the source nodes IDs.
Source node #1: all
确定之后, 会初步打印出搬运⽅案, 让⽤⼾确认,之后就会进⾏集群的 key 搬运⼯作. 这个过程涉及到数据搬运. 可能需要消耗⼀定的时间。

第三步: 给新的主节点添加从节点

光有主节点了, 此时扩容的⽬标已经初步达成. 但是为了保证集群可⽤性, 还需要给这个新的主节点添加从节点, 保证该主节点宕机之后, 有从节点能够顶上.
redis-cli --cluster add-node 172.30.0.111:6379 172.30.0.101:6379 --cluster-slave --cluster-master-id [172.30.1.110 节点的 nodeId]

代码连接集群

搭建集群之后, 主要仍然是要通过代码来访问集群的, C++可以使用 redis-plus-plus 库来使用,具体安装和使用如下文章:
只需要使⽤ RedisCluster 类代替 Redis 类即可,构造⽅法中填⼊集群中的任意节点地址。

网站公告

今日签到

点亮在社区的每一天
去签到