本文实测环境 redis:latest 拉取的Redis版本 - 7.0.11 ;
前言
上一章我们讲了redis主从+哨兵模式的搭建和理论,也提到了该模式适用于写少读多的场景,那本文就讲一下当我们项目读多写多,并有高并发的情况我们该如何使用redis的第三个模式 - cluster(集群)模式来实现项目的高可用高并发!
创建redis集群网络环境
为了主从环境的隔离性和安全性,我们先创建一个独立的docker网络区域(网段)来部署redis主从
docker network create --driver bridge --subnet 172.12.1.0/16 --gateway 172.12.1.1 redis-clusternet
上面命令的各参数解释已经在该文章详细解释,这里将不在过多叙述了!
查看网络是否新建成功
docker network ls
网络创建成功以后创建redis各个节点的配置文件
创建redis配置文件
使用脚本 创建6个redis配置文件,**注意:**cluster-announce-ip以下的配置,我是根据内网来的,如果你需要外网访问看注释进行修改配置!
for int in $(seq 1 6); \
do \
mkdir -p /var/redis/node-${int}/
touch /var/redis/node-${int}/redis.conf
cat << EDF >/var/redis/node-${int}/redis.conf
#端口号
port 6379
#网关绑定地址
bind 0.0.0.0
protected-mode no
loglevel notice
logfile /var/log/redis/node-${int}.log
dir /var/redis/node-${int}/
dbfilename dump_637${int}.rdb
requirepass 123456
#主节点密码
masterauth 123456
#是否开始 aof 持久化模式
appendonly yes
#集群开关,默认是不开启集群模式
cluster-enabled yes
#集群配置文件的名称,这个文件redis会自己生成更新
cluster-config-file nodes.conf
#集群节点超时的阀值,毫秒值
cluster-node-timeout 5000
#下面的配置是redis专门适用于docker才有得,使用docker安装部署的需要细看我的解释
#声明本节点的ip地址,如果需要外网访问就写自己服务器的外网地址,要不会外网访问不通;
cluster-announce-ip 172.12.1.10${int}
#声明本节点单机端口,如果上述填写的是外网地址,那这里就是每个节点映射到你宿主机上的端口了,就应该是 637+int变量,如果为内网地址直接就填6379,因为每个docker都算一个系统都有一个6379端口
cluster-announce-port 6379
#声明本节点集群端口,如果cluster-announce-ip是外网地址,这里就写成 1637+int变量,也是如此
cluster-announce-bus-port 16379
EDF
done
修改redis日志文件夹权限和数据文件夹的权限,让docker内的数据和日志可以生成文件!生成的数据文件和日志文件不会是 777权限,放心!
chmod -R 777 /var/log/redis
chmod 777 /var/redis/*
根据以上生成的配置文件启动各对应的redis实例
启动redis实例
启动第一个redis实例
docker run -p 6371:6379 -p 16371:16379 --name node-1 \
-v /var/redis/node-1/:/var/redis/node-1/ \
-v /var/log/redis/:/var/log/redis/ \
-d --net redis-clusternet --ip 172.12.1.101 redis:latest redis-server /var/redis/node-1/redis.conf
启动第二个redis实例
docker run -p 6372:6379 -p 16372:16379 --name node-2 \
-v /var/redis/node-2/:/var/redis/node-2/ \
-v /var/log/redis/:/var/log/redis/ \
-d --net redis-clusternet --ip 172.12.1.102 redis:latest redis-server /var/redis/node-2/redis.conf
启动第三个redis实例
docker run -p 6373:6379 -p 16373:16379 --name node-3 \
-v /var/redis/node-3/:/var/redis/node-3/ \
-v /var/log/redis/:/var/log/redis/ \
-d --net redis-clusternet --ip 172.12.1.103 redis:latest redis-server /var/redis/node-3/redis.conf
启动第四个redis实例
docker run -p 6374:6379 -p 16374:16379 --name node-4 \
-v /var/redis/node-4/:/var/redis/node-4/ \
-v /var/log/redis/:/var/log/redis/ \
-d --net redis-clusternet --ip 172.12.1.104 redis:latest redis-server /var/redis/node-4/redis.conf
启动第五个redis实例
docker run -p 6375:6379 -p 16375:16379 --name node-5 \
-v /var/redis/node-5/:/var/redis/node-5/ \
-v /var/log/redis/:/var/log/redis/ \
-d --net redis-clusternet --ip 172.12.1.105 redis:latest redis-server /var/redis/node-5/redis.conf
启动第六个redis实例
docker run -p 6376:6379 -p 16376:16379 --name node-6 \
-v /var/redis/node-6/:/var/redis/node-6/ \
-v /var/log/redis/:/var/log/redis/ \
-d --net redis-clusternet --ip 172.12.1.106 redis:latest redis-server /var/redis/node-6/redis.conf
查看生成的6个redis实例,检查容器是否启动成功
docker ps
建立集群(方案1-简单)
建立集群的方案1也就是最简单的建立方法,那个当主机那个当从机还有哈希槽的分配全部都由redis自己自动分配!
当我们6个节点都启动成功后,我么先随便进入一个redis节点容器的内部
docker exec -it node-1 /bin/bash
然后创建集群
redis-cli --cluster create 172.12.1.101:6379 172.12.1.102:6379 172.12.1.103:6379 172.12.1.104:6379 172.12.1.105:6379 172.12.1.106:6379 --cluster-replicas 1 -a 123456
- --cluster create 创建集群 , 注意 : 后面填每个redis节点配置文件中声明的ip地址和端口号 cluster-announce-ip 和cluster-announce-port,如果不一致集群创建不成功一直卡着Waiting for cluster to join
- --cluster-replicas 告诉redis一个主机需要配置几个从机 1代表一个主机需要分配1个从机
- -a 就是每个redis节点的密码
输出[OK] All 16384 slots covered. (已全部覆盖16384个插槽),集群就建立完毕了
查看集群
#进入集群 , 注意后面的-c , 没有-c 进入的是单机,有-c进入的集群
redis-cli -c
#输入节点密码,没有密码就跳过
auth 123456
#查看集群信息
cluster info
#查看集群节点信息
cluster nodes
可以看见有三个从机(slave) 还有三个主机(master)
建立集群(方案2)
方案1为redis自动分配哈希槽和主从节点,一般适用于我们的每个服务器节点性能都相差不大的情况,如果我们有的服务器性能会差点我想让他当从机,性能好点我想让他当主机这种情况的话,我们就需要手动分配主机从机和哈希槽了
- 还是先进入任意一个节点内部
docker exec -it node-1 /bin/bash
- 我们先创建主节点,把自己希望成为主节点的节点ip+端口写上,我们就主机号为101,102,105的当主节点吧
redis-cli --cluster create 172.12.1.101:6379 172.12.1.102:6379 172.12.1.105:6379
- 创建成功后,然后我们查看集群的节点信息
#进入集群 , 注意后面的-c , 没有-c 进入的是单机,有-c进入的集群
redis-cli -c
#输入节点密码,没有密码就跳过
auth 123456
#查看集群信息
cluster info
#查看集群节点信息
cluster nodes
可以看见我们3个节点全是主节点,然后我们把这3个主节点的id都记下来,也就是绿框框里面的数据;
- 给主节点去分配从机
#先退出redis集群
exit
#然后在执行一下命令
redis-cli --cluster add-node 172.12.1.103:6379 172.12.1.101:6379 --cluster-slave --cluster-master-id af687d309ab97676a9baf73d30db58b4ea357388 -a 123456
- --cluster add-node : 意思就是让172.12.1.103:6379 加入到172.12.1.101:6379所处的集群中
- --cluster-slave : 并成为这个集群的从机
- --cluster-master-id : 指定成为那个主节点的从机 , 如果不指定该主节点id,会被随机分配,这里就是填上面记录的主节点id的
[OK]New node added correctly. - 正确添加了新节点
- 再去查看集群节点信息
新添加的103节点已经成为id为af687开头的节点(105节点)的从机了,那我们也就可以自由分配redis集群中的主从机了,具体如何自由分配哈希槽方案1和方案2创建的集群都可以自由分配,细听分说!
操作集群指令
注意下列的命令都是进入集群中任意一个节点进行指令发送!
如何手动给master节点分配哈希槽
- 进入redis集群的哈希槽分配模式,后面的ip和端口填 当前集群下的任意一个节点的ip和端口即可,有节点密码记得-a+密码
redis-cli --cluster reshard 127.12.1.101:6379 -a 123456
会列出来你当前集群节点的信息,并提问你想移动多少个哈希槽
- 然后在最后一行的How many slots do you want to move (from 1 to 16384)? 后面输入你想移动多少个插槽,我这里填2000个
- 然后在What is the receiving node ID?后面填你想把这2000个哈希槽分配给那个master节点,输入该节点id,节点id上面节点信息有记录,我们这里就随便填一下,就把这2000个分配给101主机吧
- 接着就会问我们你要将那些节点的槽位移动给101主机,这里可以填 all ,all就是redis会自动在其他所有节点的哈希槽里面去提取凑够2000槽位给101主机,也可以自定义要提取那些主机的哈希槽位,可以输入多个容器id回车分割,输入done结束输入,并执行迁移
- 然后会询问你是否要继续执行重新分配计划,输入yes即可
- 然后就等待着哈希槽的迁移了,迁移完毕后我们再看一下节点信息,看一下哈希槽是否迁移成功了
可以看见 主机101覆盖的哈希槽为 0-6461 10923-11921 之前为0-5460 , 计算后就会发现101主机多了2000个哈希槽的覆盖
删除节点
可以指定一个节点的 ip+端口号+节点id去删除该节点
redis-cli --cluster del-node 172.12.1.103:6379 ab4929d85062baced5d63ff90771768489d175de -a 123456
最后可以看见103节点已经被成功删除了
一些比较常用的命令
集群状态检查
redis-cli --cluster check 172.12.1.101:6379 --cluster-search-multiple-owners -a 123456
英语好的可以自己翻译着理解,以上都表示的是我自己对此翻译的理解
集群基本信息查看
redis-cli --cluster info 172.12.1.101:6379 -a 123456
修复集群
修改集群和槽的重复分配问题
redis-cli --cluster fix 172.12.1.101:6379 --cluster-search-multiple-owners -a 12345
设置集群超时时间
在最初的每个redis节点配置中就可以配置,一般需要及时进行时间扩张的时候才会用到该命令!
redis-cli --cluster set-timeout 172.12.1.101:6379 -a 123456 10000
集群测试
#首先进入集群
redis-cli -c
#输入密码
auth 123456
#新增一条数据
set test 111000
SpringBoot连接redis集群
pom配置
注意 : 如果你使用的springboot为2.1.4-2.1.6的话不可以使用下述这样子的pom依赖,具体请看问题汇总中的问题1;
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
yml配置
spring:
redis:
password: 123456 #如果有密码的话 这里就redis的密码
cluster:
nodes: # 集群下每个节点的ip地址:端口
- 120.27.239.99:6371
- 120.27.239.99:6372
- 120.27.239.99:6373
- 120.27.239.99:6375
springboot连接redis的问题汇总
问题1 :
关于SpringBoot版本与redis版本冲突问题,如果你使用的SpringBoot为2.1.4或者2.1.6,其他版本暂时还不知道,redis版本用的7.0以上,那么当你SpringBoot连接redis单机进行写读操作他是没有问题的,也就是和你说哈希槽不合适,但是如果你连接redis集群他就会出一个很坑爹的错误 : java.lang.UnsupportedOperationException: null
出现这个问题应该就是你springboot里lettuce连接池版本和redis版本的冲突问题了,那springboot肯定不能随便换版本,一换问题比这个都多,那我们只有将springboot2.1.6版本中的lettuce给排除然后使用比较高版本boot的lettuce版本,也就是如下pom
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<!--去掉springboot2.1.6自带的lettuce版本-->
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--依赖springboot2.6.1自带的lettuce版本-->
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
<version>6.1.5.RELEASE</version>
<scope>compile</scope>
</dependency>
然后再去请求就搞定了!