文章目录
- 前言
- 5.4 分片集群
- 5.4.1 搭建分片集群
- 5.4.2 散列插槽
- 5.4.3 集群伸缩
- 5.4.3.1 需求分析
- 5.4.3.2 创建新的Redis实例
- 5.4.3.3 添加新节点到Redis集群
- 5.4.3.4 转移插槽
- 5.4.4 故障转移
- 5.4.4.1 自动故障转移
- 5.4.4.2 手动故障转移
- 5.4.5 RedisTemplate
- 5.5 小结
前言
Redis分布式缓存系列文章:
Redis从入门到精通(十三)Redis分布式缓存(一)RDB和AOF持久化、Redis主从集群的搭建与原理分析
Redis从入门到精通(十四)Redis分布式缓存(二)Redis哨兵集群的搭建和原理分析
5.4 分片集群
主从和哨兵可以解决高可用、高并发读的问题,但是依然有两个问题没有解决:海量数据存储问题、高并发写的问题。这两个问题可以通过分片集群来解决。
5.4.1 搭建分片集群
分片集群需要的节点数量较多,这里我们搭建一个最小的分片集群,包含3个master节点,每个master包含1个slave节点,实际上master节点及其slave节点的数量可以更多。其结构如下:
在同一台虚拟机开启6个Redis实例,模拟分片集群,其信息如下:
IP | 端口 | 角色 |
---|---|---|
192.168.146.128 | 8001 | master |
192.168.146.128 | 8002 | master |
192.168.146.128 | 8003 | master |
192.168.146.128 | 9001 | slave |
192.168.146.128 | 9002 | slave |
192.168.146.128 | 9003 | slave |
搭建步骤如下:
- 1)在
/usr/local/redis_sharding
中创建6个目录,名字分别是8001、8002、8003、9001、9002、9003:
- 2)在6个目录下分别创建配置文件redis.conf,其内容如下(以8001为例,其余端口应与所在目录一致):
# /usr/local/redis_sharding/8001/redis.conf
# 端口
port 8001
# 开启集群功能
cluster-enabled yes
# 集群的配置文件名称,不需要我们创建,由redis自己维护
cluster-config-file /usr/local/redis_sharding/8001/nodes.conf
# 节点心跳失败的超时时间
cluster-node-timeout 5000
# 持久化文件存放目录
dir /usr/local/redis_sharding/8001
# 绑定地址
bind 0.0.0.0
# 让redis后台运行
daemonize yes
# 注册的实例ip
replica-announce-ip 192.168.146.128
# 保护模式
protected-mode no
# 数据库数量
databases 1
# 日志
logfile /usr/local/redis_sharding/8001/run.log
- 3)在6个目录下分别启动服务
/usr/local/bin/redis-server /usr/local/redis_sharding/8001/redis.conf
/usr/local/bin/redis-server /usr/local/redis_sharding/8002/redis.conf
/usr/local/bin/redis-server /usr/local/redis_sharding/8003/redis.conf
/usr/local/bin/redis-server /usr/local/redis_sharding/9001/redis.conf
/usr/local/bin/redis-server /usr/local/redis_sharding/9002/redis.conf
/usr/local/bin/redis-server /usr/local/redis_sharding/9003/redis.conf
6个实例启动后,其进程如下:
- 4)创建集群
虽然服务启动了,但是目前每个服务之间都是独立的,没有任何关联,还需要执行命令来创建集群。
Redis5.0之前集群命令都是用redis安装包下的src/redis-trib.rb来实现的。案例使用的是Redis7.2.4版本,集群管理已经集成到了redis-cli中,格式如下:
redis-cli --cluster create --cluster-replicas 1 192.168.146.128:8001 192.168.146.128:8002 192.168.146.128:8003 192.168.146.128:9001 192.168.146.128:9002 192.168.146.128:
9003
命令说明:
-
redis-cli --cluster
:集群操作命令 -
create
:创建集群 -
--cluster-replicas 1
:指定集群中每个master的slave节点个数为1,那么节点总数÷(replicas + 1)
得到的就是master的数量。本例中即
6÷(1 + 1)=3
,因此上述命令列出的节点列表中的前3个就是master节点(8001、8002、8003),其他节点都是slave节点,随机分配到不同的master。
命令执行后:
可见,9002分配给了8001,9003分配给了8002,9001分配给了8003。输入yes继续执行:
集群创建完成。通过以下命令查看集群状态:
redis-cli -p 8001 cluster nodes
- 5)测试
尝试连接8001节点,并存储一个数据:
redis-cli -p 8001
127.0.0.1:8001> set age 21
OK
127.0.0.1:8001> get age
"21"
127.0.0.1:8001> set name aaa
(error) MOVED 5798 192.168.146.128:8002
可以发现,测试过程中出现了错误,提示我们要去8002节点操作。
实际上在进行集群操作时,需要给redis-cli
命令加上-c
参数:
127.0.0.1:8001> set name aaaaaa
-> Redirected to slot [5798] located at 192.168.146.128:8002
OK
192.168.146.128:8002> get name
"aaaaaa"
5.4.2 散列插槽
Redis会把每一个master节点映射到0~16383共16384个插槽上,在创建集群时就可以看到具体的分配情况:
Redis会根据Key值的有效部分计算插槽值(利用CRC16算法得到一个hash值,然后对16384取余,得到的结果就是插槽值),然后将数据存到插槽值对应的master节点上。 Key值的有效部分分两种情况:
- Key中包含"{}",且“{}”中至少包含1个字符,则“{}”中的部分是有效部分;
- key中不包含“{}”,整个key都是有效部分。
例如:
127.0.0.1:8001> set test aaa
-> Redirected to slot [6918] located at 192.168.146.128:8002
OK
在8001节点上执行set test aaa
时,对test
进行插槽值计算得到的结果是6918,因此要存储到8002节点上。
127.0.0.1:8003> get test
-> Redirected to slot [6918] located at 192.168.146.128:8002
"aaa"
在8003节点上执行get test
时,也要根据插槽值去8002节点上查找。
5.4.3 集群伸缩
Redis提供了很多操作集群的命令,可以通过redis-cli --cluster help
命令查看具体有哪些。
5.4.3.1 需求分析
现在有一个需求:向集群中添加一个新的master节点,并向其中存储test=bbb。
换句话说,就是添加一个新的master节点到集群中,并将部分插槽分配到给新的master节点。
5.4.3.2 创建新的Redis实例
在/usr/local/redis_sharding
目录下创建文件夹8004,并拷贝配置文件redis.conf,将其中的端口、目录等配置修改为8004:
启动8004节点:
/usr/local/bin/redis-server /usr/local/redis_sharding/8004/redis.conf
5.4.3.3 添加新节点到Redis集群
执行以下命令:
redis-cli --cluster add-node 192.168.146.128:8004 192.168.146.128:8001
查看集群状态:
redis-cli -p 8001 cluster nodes
如图,8004节点加入了集群,并且是一个master节点,但是其插槽数量为0,因此没有任何数据可以保存到8004节点上。
5.4.3.4 转移插槽
由前面的测试可知,Key值为"test"
时其插槽值为6918,我们可以将5461~7461共2000个插槽由8002转移到8004,其命令格式为:
具体的操作步骤如下:
执行以下命令:
redis-cli --cluster reshard 192.168.146.128:8001
得到如下反馈:
询问要移动多少个插槽,我们计划是2000个:
询问要使用哪个节点来接收这些插槽,我们计划是8004节点,因此这里输入8004节点的ID:
询问要从哪个节点移动这些插槽,我们计划是8002节点,因此这里输入8002节点的ID:
如果这里没有输入8002节点的ID,而是输入all,则代表从全部master节点中各移动一部分。
然后再输入done,完成插槽移动的准备工作:
询问是否确认转移,输入yes,开始执行插槽的移动。移动完成后,再次查看集群的状态:
可见,插槽5461~7460以从8002节点移动到了8004节点。
下面进行测试:
127.0.0.1:8001> set test bbb
-> Redirected to slot [6918] located at 192.168.146.128:8004
OK
可见,数据已成功保存到8004节点,需求成功实现。
5.4.4 故障转移
目前,8001、8002、8003、8004都是master节点,如果其中一个实例宕机,会发生什么呢?
5.4.4.1 自动故障转移
执行以下命令,停止8002实例:
redis-cli -p 8002 shutdown
再查询集群状态,集群已识别到8002宕机,并把9001实例提升为master:
当8002再次启动时,自动成为slave节点:
5.4.4.2 手动故障转移
在某个slave节点上执行cluster failover
命令,可以手动让集群中的某个master节点宕机,然后自己提升为master节点,实现无感知的数据迁移。
例如,在进行自动故障转移时,8002节点成为了slave节点。我们可以在8002节点上执行cluster failover
命令,就可以重新夺回master的地位。
127.0.0.1:8002> cluster failover
OK
查看集群状态:
可见,8002节点重新夺回master地位,9001节点降为slave节点。
5.4.5 RedisTemplate
RedisTemplate底层同样基于lettuce实现了对Redis分片集群的支持,使用步骤与主从集群基本一致,只是在配置文件application.yml中略有差异:
# src/main/resources/application.yml
spring:
redis:
cluster:
nodes:
- 192.168.146.128:8001
- 192.168.146.128:8002
- 192.168.146.128:8003
- 192.168.146.128:8004
- 192.168.146.128:9001
- 192.168.146.128:9002
- 192.168.146.128:9003
下面做个简单的测试:调用/redis/set/test/ccc
接口,由日志可知写操作由master节点8004实例完成,这个之前的测试结果是一致的:
5.5 小结
第5章到此就学习完毕了,本章的主题是:Redis分布式缓存。回顾一下本章的学习的内容:
(十三)RDB、AOF持久化的原理;Redis主从复制集群的搭建和原理分析。
(十四)Redis哨兵集群的搭建和原理分析。
(十五)Redis分片集群的搭建和原理分析。
更多内容请查阅分类专栏:Redis从入门到精通
感兴趣的读者还可以查阅我的另外几个专栏:
- SpringBoot源码解读与原理分析(已完结)
- MyBatis3源码深度解析(已完结)
- 再探Java为面试赋能(持续更新中…)