Redis之Redis Cluster的使用
一、Redis Cluster 简介
Redis Sentinel 水平扩容一直都是一个痛点,因为水平扩容牵涉到数据的迁移。迁移过程一方面要保证自己的业务是可用的,一方面要保证尽量不丢失数据所以数据能不迁移就尽量不迁移。针对这个问题,Redis Cluster就应运而生了。
Redis Cluster 是 Redis 的分布式解决方案,在3.0版本正式推出,有效地解决了 Redis 分布式方面的需求。当遇到单机内存、并发、流量等瓶颈时,可以采用 Cluster 架构方案达到负载均衡的目的。
二、Redis Cluster 和哨兵集群的比较
哨兵集群:本质上还是一个主从模式下的集群方案,增加一个选举机制,当主节点宕机之后会从所有节点中选出新的主节点,选举机制的实现依赖于sentinel
进程。这种模式基本已经可以实现高可用,读写分离 ,但是在性能,存储量上还是不够好。
cluster
集群:是Redis
的一种分布式解决方案,在3.0版本中正式提出,这个方案把整个数据集按照分区规则映射到多个节点的问题,即把数据集划分到多个节点上,每个节点负责整个数据的一个子集。Redis Cluster
槽的范围是0 ~ 16383。槽是集群内数据管理和迁移的基本单位。主要目的是为了方便数据的拆分和集群的扩展,每个节点负责一定数量的槽。通过slot = CRC16(key)&16383
计算所在卡槽的节点位置。
三、搭建Redis Cluster集群
结构图
配置文件
# ip监控
bind 0.0.0.0
protected-mode no
# 端口 修改
port 7000
# 后台运行
daemonize yes
# 工作目录
dir ./
# pid 修改
pidfile "/var/run/redis_7001.pid"
# 日志名 修改
logfile "redis_7001.log"
# RDB同步数据 修改
dbfilename "dump_7001.rdb"
# AOF同步
appendonly yes
# 修改
appendfilename "appendonly_7001.aof"
# AOF 策略
appendfsync everysec
# 失效消息通知配置
# notify-keyspace-events "xE"
# 开启cluster, 去掉注释
cluster-enabled yes
# 自动生成 修改
cluster-config-file cluster_7001.conf
# 节点通信时间
cluster-node-timeout 15000
将这配置文件复制六份需要修改的地方,修改之后。
启动脚本
#!/bin/bash
# 整个测试环境的根目录
ROOT_PATH=/opt/redis-cluster-self-service
# 存放redis-server的目录
REDIS_SERVER=/opt/redis-cluster-self-service/redis-master/bin/redis-server
echo ">>> 清除启动的 Redis cluster 集群...";
for item in `ps -ef | grep -v grep | grep redis | awk '{print $2}'`
do
echo $item
kill -9 $item
done
echo ">>> 成功清除启动的 Redis cluster 集群...";
echo ">>> 启动redis cluster 集群...";
for item in {0..5}
do
$REDIS_SERVER $ROOT_PATH/redis-node-700${item}/redis-700${item}.conf;
if [ $? == 0 ];then
# sleep 5s;
echo "启动端口为700${item}的Redis服务器成功";
else
echo "启动端口为700${item}的Redis服务器失败";
fi
done
echo ">>> 启动redis cluster 集群结束";
echo ">>> 检测是否启动成功...";
ps -ef | grep -v grep | grep redis
启动集群
[root@long-test redis-cluster-self-service]# ./start.sh # chmod +x start.sh赋予权限
>>> 清除启动的 Redis cluster 集群...
17171
>>> 成功清除启动的 Redis cluster 集群...
>>> 启动redis cluster 集群...
启动端口为7000的Redis服务器成功
启动端口为7001的Redis服务器成功
启动端口为7002的Redis服务器成功
启动端口为7003的Redis服务器成功
启动端口为7004的Redis服务器成功
启动端口为7005的Redis服务器成功
>>> 启动redis cluster 集群结束
>>> 检测是否启动成功...
root 17237 1 0 05:59 ? 00:00:00 /opt/redis-cluster-self-service/redis-master/bin/redis-server 0.0.0.0:7000 [cluster]
root 17242 1 0 05:59 ? 00:00:00 /opt/redis-cluster-self-service/redis-master/bin/redis-server 0.0.0.0:7001 [cluster]
root 17244 1 0 05:59 ? 00:00:00 /opt/redis-cluster-self-service/redis-master/bin/redis-server 0.0.0.0:7002 [cluster]
root 17249 1 0 05:59 ? 00:00:00 /opt/redis-cluster-self-service/redis-master/bin/redis-server 0.0.0.0:7003 [cluster]
root 17257 1 4 05:59 ? 00:00:00 /opt/redis-cluster-self-service/redis-master/bin/redis-server 0.0.0.0:7004 [cluster]
root 17259 1 11 05:59 ? 00:00:00 /opt/redis-cluster-self-service/redis-master/bin/redis-server 0.0.0.0:7005 [cluster]
[root@long-test redis-cluster-self-service]#
连接其中一个Redis
[root@long-test redis-cluster-self-service]# redis-cli -p 7000 # 连接7000端口
127.0.0.1:7000> set name 1234
(error) CLUSTERDOWN Hash slot not served # 未分配卡槽
分配卡槽
[root@long-test redis-cluster-self-service]# redis-cli --cluster create 192.168.252.131:7000 192.168.252.131:7001 192.168.252.131:7002 192.168.252.131:7003 192.168.252.131:7004 192.168.252.131:7005 --cluster-replicas 1
--cluster-replicas 1
:是表示主节点和从节点为1:1的比例(一主一从)的结构。
分配的卡槽情况:
最后分配结果:
再次连接其中一个redis
[root@long-test redis-cluster-self-service]# redis-cli -p 7000
127.0.0.1:7000> set name 123456
(error) MOVED 5798 192.168.252.131:7001 # 仍然不能写入值,提示我们key对应的卡槽在7001这个redis上
127.0.0.1:7000>
我们需要在连接的时候添加一个重定向的参数:
[root@long-test redis-cluster-self-service]# redis-cli -p 7000 -c # -c redis的客户端会为我们自动重定向
127.0.0.1:7000> set name 123456
-> Redirected to slot [5798] located at 192.168.252.131:7001
OK
192.168.252.131:7001> # 现在已经在redis的7001这个服务器上了
四、 Redis Cluster 扩容
复制上面的配置文件,然后启动服务:
7006
和7007
就是我们新需要扩容的redis
服务。
Redis
将节点扩容到Redis
集群中
先添加一个主节点
# 将7006 扩容主节点
[root@long-test redis-cluster-self-service]# redis-cli --cluster add-node 192.168.252.131:7006 192.168.252.131:7000
扩容主节点之后的集群节点情况
再添加一个从节点:
# 将7007 扩容从节点
[root@long-test redis-cluster-self-service]# redis-cli --cluster add-node 192.168.252.131:7007 192.168.252.131:7000 --cluster-slave --cluster-master-id 22ebb08e9461445d8f77ca650fca7d1a777928aa
# --cluster-master-id 后面添加的是主节点的ID, 从上图命令中可以得到
再次查看添加从节点之后集群情况:
这样就说明我们添加节点成功了,但是我们还需要分配卡槽,这样的话添加的节点才可以读写数据。
分配卡槽
在我们刚才是三台的时候每台redis
分到的卡槽是:16384/3=5461
,其中一个节点时5462
个,剩下两个是5461
。
现在我们扩容的时候是4台redis
, 平均分配到四台上,那我们每一台16384/4=4096
。
分配的方法有两种方式:
all
: 均摊,从当前的每个节点中分配一部分到新的节点中done
: 选择某一个节点进行分配。
接下来就是yes
,等待分配移动节点结束,在这期间是无法读写的。
分配之后的卡槽情况:
分配之后我们进行读写:
[root@long-test redis-cluster-self-service]# redis-cli -p 7000 -c
127.0.0.1:7000> set yyyy 123456 # 可以写入7006节点的数据了
-> Redirected to slot [10980] located at 192.168.252.131:7006
OK
192.168.252.131:7006>
五、 Redis Cluster 缩容
缩容的命令:
[root@long-test redis-cluster-self-service]# redis-cli --cluster reshard 192.168.252.131:7000 --cluster-from 532c30c5d91a4011145ce7e92d4949fdf056bf73 --cluster-to 51e81d10bbd2cb399e91273fc52831c24a82dac9 --cluster-slots 4096
# --cluster-from 要减少的节点ID
# --cluster-to 要移动到的节点ID
# --cluster-slots 4096 移动的节点
缩容之后的卡槽情况:
六、Redis Cluster 宕机自动选举
将7006
节点杀掉,我们看一下7007
是否会变为主节点:
将7006
节点启动之后我们会发现变为从节点:
七、 Springboot整合Redis Cluster
这里我们每个redis节点配置一个密码:
在redis的配置文件中添加一个密码:
requirpass 123456
重新创建分配卡槽
[root@long-test ]# redis-cli --cluster create 192.168.252.131:7000 192.168.252.131:7001 192.168.252.131:7002 192.168.252.131:7003 192.168.252.131:7004 192.168.252.131:7005 192.168.252.131:7006 192.168.252.131:7007 -a 123456 --cluster-replicas 1
# -a 123456 是为了设置整个集群的密码123456
依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
配置文件
spring:
redis:
password: 123456
cluster:
# 所有节点列表
nodes:
- 192.168.252.131:7000
- 192.168.252.131:7001
- 192.168.252.131:7002
- 192.168.252.131:7003
- 192.168.252.131:7004
- 192.168.252.131:7005
- 192.168.252.131:7006
- 192.168.252.131:7007
# 最大重定向次数
max-redirects: 4
lettuce:
pool:
# 连接池最大连接数
max-active: 8
# 连接池最大阻塞等待时间
max-wait: -1ms
# 连接池中最大空闲连接数
max-idle: 10
# 连接池中最小空闲连接数
min-idle: 5
使用:
@RestController
public class RedisController {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@GetMapping("/set_key")
public String setKey() {
stringRedisTemplate.opsForValue().set("order_name", UUID.randomUUID().toString());
System.out.println("设置的key");
return "success";
}
}
查看我们写入的值:
[root@long-test redis-cluster-self-service]# redis-cli -p 7000 -a 123456 -c
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:7000> get order_name # 重定向到7001节点
-> Redirected to slot [4291] located at 192.168.252.131:7001
"407f7841-3054-4775-ac00-9b03d502a164"
192.168.252.131:7001>
八、主从、哨兵、集群的辨析
最后我们在看一下Redis
中多机数据库实现的这三种模式的总结和辨析:
- 主从复制:集群方式里最简单的。它主要是基于Redis的主从复制特性架构的。通常我们会设置一个主节点,N个从节点;默认情况下,主节点负责处理使用者的IO操作,而从节点则会对主节点的数据进行备份,并且也会对外提供读操作的处理。
- 哨兵集群:基于主从模式做的一定变化,它能够为Redis提供了高可用性。在实际生产中,服务器难免不会遇到一些突发状况:服务器宕机,停电,硬件损坏等。这些情况一旦发生,其后果往往是不可估量的。而哨兵模式在一定程度上能够帮我们规避掉这些意外导致的灾难性后果。这种模式下每台redis服务器都存储相同的数据,很浪费内存;并难以支持现线扩容,横向扩展比较麻烦。
- Redis 集群是一个提供在多个Redis间节点间共享数据的程序集。也就是分布式存储,也就是说每台redis节点上存储不同的内容。并且仍然具有主从和哨兵的优点。当其中一个主节点宕机需要半数以上的主节点确定才会从从节点中选举出新的主节点。