[Redis#19] 集群 | 数据分片 | docker模拟 | 故障转移 | 集群扩容
本文探讨了Redis集群的构建与管理,涵盖数据分片算法(如哈希槽分区)、Docker环境下的集群搭建步骤,以及故障判定和迁移机制。通过详细实验,演示集群扩容方法,确保高可用性和数据一致性。
目录
- 本章节相关操作不需要记忆,后续工作中如果用到了能查到即可。
- 重点在于理解流程和原理。
基本概念
- 上篇文章讲述的哨兵模式, 提高了系统的可用性. 但是真正用来存储数据的还是 master 和 slave 节点. 所有的数据都需要存储在单个 master 和 slave 节点中.
- 如果数据量很大, 接近超出了 master/slave 所在机器的物理内存, 就可能出现严重问题了.
- 虽然硬件价格在不断降低, 一些中大厂的服务器内存已经可以达到 TB 级别了, 但是 1TB 在当前这个 "大数据" 时代, 俨然不算什么, 有的时候我们确实需要更大的内存空间来保存更多的数据.
如何获取更大的空间?
加机器即可! 所谓 "大数据" 的核心, 其实就是一台机器搞不定了, 用多台机器来搞.
Redis 的集群就是在上述的思路之下, 引入多组 Master/Slave, 每一组 Master/Slave 存储数据全集的一部分, 从而构成一个更大的整体, 称为 Redis 集群 (Cluster)
集群
集群这个词,可以从广义上来理解,也可以从狭义上来理解。
- 其中广义的集群,只要是多个机器,构成了分布式系统。我们前面学过的哨兵模式,也可以算作是一种广义上的集群。
- 狭义的集群,是 Redis 提供的一种集群模式,在这个集群模式之下,主要解决存储空间不足的问题,即 拓展存储空间。
我们前面的哨兵模式提高了系统的可用性,哨兵模式中,本质上还是 Redis 主从节点存储数据,其中要是请求一个主节点/从节点,就得存储整个数据的“全集”。
- 但是集群中主要要解决的问题就是要 引入多台机器, 每台机器存储一部分数据。
- 只要机器规模足够大, 就可以存储任意数据的大小了。比如:
- Redis 的集群通过引入多组 Master/Slave 来分散数据存储压力。
- 每一组 Master/Slave 存储数据全集的一部分,构成一个更大的整体。
- 假定整个数据 全集为 1TB,三组 Master/Slave 可以每组存储 1/3 的数据。
- 每个 Slave 是对应 Master 的备份(Master 故障时,Slave 会补位成 Master)。
- 每个 红框部分称为一个分片 (Sharding),用于进一步扩展存储容量。
关于使用硬盘代替内存
- 硬盘虽然可以存储更多数据,但访问速度远慢于内存。
- 在某些应用场景(如搜索引擎),既需要存储较多数据,又希望有非常高的读写速度。这时我们就可以引入 redis 集群啦
这其中每个服务器集群上都需要存储一定规模的数据,也就是把数据分为了多份,但是数据在分成多份的时候,应该怎么分?这就是我们接下来需要主要研究的问题。
数据分片算法
分片的核心思路是用多组机器来存数据的每个部分,那么接下来的核心问题就是,给定一个数据(一个具体的 key),那么这个数据应该存储在哪个分片上?读取的时候又应该去哪个分片读取?围绕这个问题,业界有三种比较主流的实现方式:
- 哈希求余
- 一致性哈希算法
- 哈希槽分区算法
1. 哈希求余
哈希求余,就是借鉴了哈希表的基本思想
借助哈希函数,把一个 key 映射到整数,再针对数据的长度,求余就可以得到一个数组的下标。
哈希求余的分片算法具体是什么样子的呢?
- 比如有三个分片,编号 0 1 2,此时就可以针对要插入的数据的 key 计算出一个哈希值
- (计算 哈希值的算法,一般是针对一个字符串里面的内容进行一系列的变换,比如 md5 算法就是一种哈希算法,它是把一个字符串变换成为一个 16 进制的数字)。
- 在把这个 哈希值余上一个分片个数,就会得到一个下标。此时就可以把这个数据放到该下标对应的分片中了。
- 比如,hash(key) % N => 0,由于求出的余数是 0,此时这个 key 对应的数据就要 存储在 0 号分片中。
- 后续查询 key 的时候也是同样的算法。只要 key 是一样的,hash 函数式一样的,得到的分片的值就是一样的。
- 随着业务逐渐增长,数据变多的时候,仅有的几个分片就不足以保存数据了,这就需要对集群进行扩容,引入新的分片。
这时候,哈希求余算法的缺点就体现出来了,就是在增加集群容量,需要对数据进行 搬运的时候,开销非常大,很多数据都需要搬运。原因就是,扩容后 N
的值会变大,那么原先的求余就不再适用了,此时要把 所有数重新计算。计算完毕后,还要面临复杂的搬运数据的过程。,大部分的数据都是需要搬运的,这就是扩容的开销非常大。
从上图中可以看到,其中的 21 个数据,只有 3 个 key 没有被搬运,其他的 key 都是搬运过的。
当然,哈希求余的分片算法也是有一定优点的,那就是 简单高效,数据分配比较均匀。
2 一致性哈希算法
在哈希求余这种操作中,当前的 key 属于哪个分片是交替的。例如某些数据的 hash 值分别是 102, 103, 104,这些数据在对 3 求余后,得到的值分别是 0, 1, 2,它们哈希求余求出的值是交替的,交替分布在不同的集群中。
而在一致性哈希算法中,我们改进了这种交替存储的方式为连续存储。一致性哈希算法的过程如下:
- 数据空间映射:首先把数据空间全部映射到一个圆环上,数据按照顺时针方向增长。
- 分片定位:假设当前存在三个分片,将这些 分片放到圆环的某个位置。
- Key 映射与分配:对于每一个 key,通过哈希函数 计算得到 哈希值 H,并将 H 映射到圆环上的对应位置。从 H 所在的位置开始,顺时针向下找,找到的第一个分片即为该 key 所从属的分片。
这相当于 N 个分片的位置将整个圆环分成了 N 个管辖区间,key 的哈希值落在某个区间内,就归该区间管理。
在这种一致性哈希算法情况下,如果需要对数据进行扩容,原有分片在环上的位置不动,只需要在环上 安排一个新的分片(如下图粉色区域)。
此时只需把 3 号分片上的部分数据搬运给新增的分片(如 4 号分片),而其他分片管理的区间保持不变。
这种方式 相比哈希求余减少了数据搬运成本,但可能导致各分片的数据量不均匀,出现 数据倾斜 现象。
3. 哈希槽分区算法 (Redis 使用)
- 求余%:扩容不便
- 一致性分片:数据倾斜
为了解决上述问题,Redis 集群引入了哈希槽算法,其公式为:
hash_slot = crc16(key) % 16384
- 这里 CRC 是一种哈希算法,16384 等于 16*1024 或者说是 2^14。
- 此算法 结合了 一致性哈希 和 哈希求余 的特点
- 将哈希值映射到 16384 个槽位上,然后把这些 槽位均匀地分配给每个分片。每个分片会使用“位图” 这样的数据结构来记录自己持有的槽位号,用 0/1 表示是否持有该槽位。
假设当前有三个分片,一种可能的分配方式如下:
- 0 号分片: [0,5461],共 5462 个槽位
- 1 号分片: [5462,10923],共 5462 个槽位
- 2 号分片: [10924,16383],共 5460 个槽位
实际上,分片方式非常灵活,每个分片持有的 槽位号可以是连续或不连续的。尽管不是严格意义上的均匀,但差异很小,使得数据分布较为均衡。
当需要进行扩容时,比如新增一个 3 号分片,可以通过重新分配原有的槽位来实现:
- 0 号分片: [0,4095],共 4096 个槽位
- 1 号分片: [5462,9557],共 4096 个槽位
- 2 号分片: [10924,15019],共 4096 个槽位
- 3 号分片: [4096,5461]+[9558,10923]+[15019,16383],共 4096 个槽位
此时,每个分片分出一部分槽位给新来的分片,并且保证最终所有分片持有的槽位个数接近,此处因为 16384 / 4
可以除尽,所以最终四个分片的槽位数目完全相同。
最后进行数据拷贝时,只需要0 1 2
三个分片,分别单向拷贝一部分数据给3
号分片即可。
此外,还有一些关于 Redis 集群的问题需要注意:
Redis 集群最多有 16384 个分片吗?
在 Redis 集群中,key 是要先映射到槽位上,再映射到分片上的。这种设计的目的是为了确保数据分布的均匀性:
- 如果每个分片包含的槽位较多,并且槽位个数相当,那么可以认为每个分片包含的 key 数量也是相等的,从而保证了数据分布的均匀性。
- 然而,如果每个分片包含的槽位非常少,槽位的数量可能无法直观地反映出 key 的数量,这种情况之下,数据的均匀性就难以保证。
- 此外,如果每个分片中包含的槽数非常少,则会导致集群中的服务器规模变得非常庞大,随着服务器数量的增加,出现故障的概率也会相应增大。
为什么是
16384
个槽位?
- 节点之间通过心跳包通信,心跳包中包含了该节点持有哪些槽位,这个是使用位图这样的数据结构表示的。
- 表示 16384 个槽位需要的位图大小是 2KB,如果给定的槽位数更多了,此时就需要消耗更多的空间。
- 这对于内存来说不算什么,但是 在频繁的网络心跳包中,还是一个不小的开销,因为网络带宽是比内存更稀缺的资源
- 另一方面,Redis 集群一般不建议超过 1000 个分片。
16384
个槽位,对于最大 1000 个分片来说是足够用的,同时也会使对应的槽位配置位图体积不至于很大
参考:
Docker搭建集群
接下来使用docker
搭建一个如下集群,拓扑结构如下:
注意
- 本示例中我们将创建11个Redis节点
- 其中前9个用于演示集群的搭建,后两个用于演示集群扩容。
i:创建目录和配置文件
首先,创建一个名为 redis-cluster
的目录,并在该目录下创建两个文件:
编写 generate.sh
脚本
generate.sh
内容如下,此脚本将为每个 Redis 实例创建配置文件并设置不同的 IP 地址:
#!/bin/bash
# 创建并配置前9个节点
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
# 创建并配置第10和11个节点(用于后续扩容)
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
C++ 和 Java 中的循环
- C++:
range based for
(C++ 也有std::for_each
,STL 中的一个函数) - Java:
for each
Shell 脚本中的循环如上
解释
seq
: 一个 Linux 命令,生成[1, 9]
。\
: 续行符,把下一行的内容和当前行合并成一行。
-
- 默认情况下,shell 要求把所有的代码都写到一行里,使用续行符来换行。
{ }
: 在 shell 中表示变量,不是表示代码块。
-
- 对于
for
,使用do
和done
来表示代码块的开始和结束。 - 循环体内的代码。
- 对于
- 字符串拼接:在 shell 中拼接字符串是直接写到一起,而不需要使用
+
。
预期效果
- 得到 11 个目录,每个目录里都有一个配置文件。
- 配置文件中,IP 地址各不相同。
注意:cluster-announce-ip 172.30.0.10${port}
的值对于每个实例是不同的,以确保它们在网络中的唯一性。
执行生成命令
运行以下命令以执行 generate.sh
脚本,这将在 redis-cluster/
目录下生成相应的子目录及配置文件:
bash generate.sh
生成后的目录结构应类似于:
每个 redis.conf
文件的内容除了 cluster-announce-ip
不同外,其他部分都相同。例如,redis1/redis.conf
包含如下内容:
配置说明:
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
: 节点自身的总线端口,用于集群管理信息交互。
注意:
- cluster-announce-ip: Docker 容器的 IP 地址。
- port: 容器内的 Redis 端口。
- 业务端口: 用于业务数据通信。(eg. 客户端访问的
- 管理端口: 用于管理任务通信。
故障处理
- 如果某个分片中的 Redis 主节点挂了,就需要让从节点成为主节点,就需要通过刚才 管理端口 来完成相应的操作。
- 服务器端口绑定: 一个服务器可以绑定多个端口号。
ii:编写 docker-compose.yml
接下来,我们需要编写 docker-compose.yml
文件来定义 Docker 容器网络和服务。以下是配置示例:
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
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
网络配置
- subnet: 此处为了后续创建静态的 IP,就需要先手动创建出网络,同时给这个网段分配 IP。这里分配的 网络号是 172.30.0,其中这个网络号是私网格式的一种,需要注意的是,不能和当前主机上现有的其他网段冲突,
0/24
是主机号。
- volumes: 配置文件映射,确保容器内的配置文件与宿主机上的配置文件同步更新。
- ports: 端口映射,需要注意的是,映射右边的端口必须和配置文件中的保持一致。
- ipv4_address: 静态配置的网络 IP,这里的 IP 也必须和之前的配置文件中的一致。
启动容器之前,要把之前测试的容器关掉,避免冲突
博主在测试机上没什么有用的,就粗暴的直接全都删掉了
由于要启动是一个容器,所以上面的文件会比较长。
启动容器:
docker compose up -d
此时十一个容器就启动了。
但是这些容器目前还是单独的节点,尚未构成集群。
iii: 构建集群
接下来需要把这些服务容器全部构建为集群,使用如下命令:
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 2
表示每个主节点需要两个从节点备份。设置了这个配置之后,Redis 就会知道,每 3 个节点是一组(一个分片)。但是分配的时候,谁是主节点,谁是从节点,都是随机的。
这样redis
就会依据规则自动构建集群,每三个节点构成一个分片(因为指定了一个主有两个从),并且会自动构建主从关系。
输入命令后,出现以下界面:
- 1 部分,是信号槽的分配部分,可以看到
redis
内部采用了连续分配的方式,将信号槽均匀的分配给三个分片。 - 2 部分,是主从关系的建立部分,第一行表示:
172.30.0.105:6379
成为172.30.0.101:6379
的从节点。那么这六行日志,就表示xxx.101
、xxx.102
、xxx.103
成为了三个主节点,其余的节点成为这三个的从节点。 - 3 部分,是一段日志,就是具体把那一部分槽位具体分配给哪一个分片,比如
xxx.101
拿到了[0-5460]
的槽位号。
输入 yes
之后才会真正创建。
见到 [OK]
之后说明集群建立完成。
连接并验证集群
使用客户端连接集群中的任何一个节点,都相当于连上了整个集群。:
redis-cli -h 172.30.0.101 -p 6379
在客户端中,我们使用 cluster nodes
来查看当前集群的信息。
重定向
尝试插入数据:
报错了,因为当前集群发生了分片,每个分片都只能存储一部分数据,key1
经过哈希运算,发现并不是这个节点可以存储的值,于是就报错了。
想要解决这个问题,可以在启动时加上-c
选项,此时插入数据,会自动重定向到对应的节点。
如图,每次操作数据是,如果该数据不属于当前分片,就会触发一次重定向,自动跳转到对应的客户端。命令行前面的 ip 一直在改变,这就说明我们的客户端一直在切换。
但是redis
中,有一些命令同时操作多个key
,比如最后一个命令mget
,此时又报错了。因为这几个key
属于不同分片,那么就无法同时处理,因此在集群的情况下,最好不要一次性操作多个key
。
主节点宕机自动处理流程
如果在集群中,某一个分片的主节点宕机了,会发生什么?在部署集群时,并没有引入哨兵节点,但是集群也会完成哨兵的工作,如果主节点宕机了,集群会自动完成重新选主的过程。
接下来就讲解集群中是如何完成故障转移的。
故障判定
Redis 集群中的所有节点会周期性地使用心跳包进行通信,确保各节点之间的连接状态和集群配置信息的同步。以下是心跳包交互的具体过程:
- 心跳包通信:节点A给节点B发送
ping
包,B接收到后返回一个pong
包。这些消息除了类型属性外,其余部分相同,并包含以下集群配置信息:
-
- 节点ID
- 所属分片
- 主/从角色
- 附属主节点(如果为从节点)
- 持有的哈希槽位图
- 随机化心跳检测:每个节点每秒钟随机选择一部分节点发送
ping
包,而非向所有节点发送,以减少大量节点存在时的心跳包数量。 - PFAIL 状态:当节点A尝试与节点B通信未果时,A首先尝试重置TCP连接;若仍然失败,则将B标记为
PFAIL
(主观下线)状态。 - Gossip协议确认:一旦A判定B为
PFAIL
,它会通过内置的Gossip协议与其他节点沟通,确认B的状态。每个节点维护自己的“下线列表”,反映其视角下的故障节点。 - FAIL 状态:如果多数节点(超过半数)也认为B处于
PFAIL
状态,那么A将正式把B标记为FAIL
(客观下线),并通知其他节点更新状态。
故障迁移
当一个节点被标记为FAIL
时,根据该节点的角色,可能触发不同的响应:
- 从节点故障:如果是从节点,通常不需要特别处理,因为它们不直接服务客户端请求。
- 主节点故障:如果故障节点是主节点,则需要进行故障迁移,流程如下:
-
- 资格审查:从节点检查自身是否符合晋升条件,即与原主节点的最后通信时间不超过设定阈值。
- 休眠等待:符合条件的从节点进入一段随机的休眠期,
休眠时间=500ms基础时间+[0,500ms]随机时间+排名*1000ms
,offset
的值越大,则排名越靠前(越小)。这一策略有助于防止多个从节点同时竞选。 - 拉票选举:休眠结束后的 从节点开始向其他集群的主节点拉票。只有主节点有投票权,且每个主节点只能投一票。
- 晋升为主:获得超过半数主节点支持的从节点晋升为主节点,并执行
SLAVEOF NO ONE
命令脱离原主节点控制。并且让同一分片中的其它节点执行slaveof
- 最后,新的主节点会把自己成为主节点的消息,同步给其他集群的节点,大家也都会更新自己保存的集群结构信息
此过程类似于 Raft算法,旨在选出网络状况较好的节点作为新的主节点,保证集群的服务连续性和数据一致性。
Fail 状态的影响
在某些情况下,单个节点的故障可能导致整个集群进入fail
状态,具体情形包括但不限于:
- 某一分片内的所有主节点和从节点都不可用。
- 某一分片内主节点故障且 无可用从节点可晋升。
- 超过半数的主节点失效。
实验
如图:
首先通过docker stop redis1
,关掉了redis1
节点,也就是xxx.101
下线了,而这是一个主节点。登录6372
端口的客户端,查看当前集群,可以发现xxx.106
成为了新的主节点,而xxx.105
原先是xxx.101
的从节点。
重启redis1
,其变为了reids5
的从节点。
此处 集群的故障转移,和哨兵的故障转移是有一些差别的
- 哨兵:sdown/odown
- 集群:PFAIL/FAIL
集群扩容
一、加入集群
- 命令格式:
-
- 使用
--cluster add-node
选项将新节点添加到集群。
- 使用
- 具体操作:
-
- 新增节点:要增加到集群的节点。
- 集群任意节点:用于标识要加入哪一个集群。
redis-cli --cluster add-node 172.30.0.110:6379 172.30.0.101:6379
这样就可以把xxx.110
节点加入到集群中,登入任意客户端查看:
通过上述命令,可以将 xxx.110
节点加入到集群中。登录任意客户端查看,可以看到集群内部已有 xxx.110
,且是一个主节点。但需要注意的是,新增节点没有分配哈希槽。
二、分配哈希槽
- 命令格式:
-
- 使用
--cluster reshard
选项给新节点分配哈希槽(注意是reshard
不是shared
)。
- 使用
redis-cli --cluster reshard 172.30.0.101:6379
执行步骤:
- 系统会询问要移动多少个 slots(哈希槽)。假设需要移动4096个哈希槽给新节点,则输入
4096
。 - 接着询问将这些哈希槽移动给哪个节点。此时应选择 哈希槽为 0的主节点,并复制其ID。
- 最后询问从哪些节点中空出这些哈希槽。可以 选择
all
表示从所有现有节点平均提取,或自己指定节点ID,以done
结束。 - 最终向用户确认是否要执行该操作。
执行完毕后,进入任意客户端查看集群现状,可以看到新节点获得了三个范围的哈希槽。
问题:搬运哈希槽的过程可能比较久,在此期间用户的访问合法性如何?
- 大部分哈希槽在搬运过程中仍可正常访问。
- 如果 用户访问正在移动的哈希槽,则可能会导致访问失败。
三、添加从节点
- 命令格式:
-
- 使用
add-node
命令配合--cluster-slave
和--cluster-master-id
选项来添加从节点。
- 使用
redis-cli --cluster add-node 新节点 --cluster-slave --cluster-master-id 主节点的ID
- 参数说明:
-
--cluster-slave
:指定新添加的节点作为从节点。--cluster-master-id
:后面跟着的是主节点的ID,表示该节点从属于哪一个节点。
redis-cli --cluster add-node 172.30.0.111:6379 172.30.0.101:6379 --clusterslave --cluster-master-id [172.30.1.110 节点的 nodeId-->] 7ec6d4a0e616916afab017f30d9a1434e375e80a
此时扩容目标初步达成,但是为了保证整个集群的可用性,还需要给主节点添加一些从结点,保证主节点宕机之后,有接班人~
sum:
主从复制:分担了读取压力
哨兵:监控,稳健性提高
集群:存储数据量 提升
更多推荐
所有评论(0)