Redis分片集群 - 解决高并发写的问题
分片集群与哨兵集群的区别
-
主从和哨兵集群:解决了高可用、高并发读问题,但无法解决海量存储和高并发写的问题
-
分片集群:可以解决高并发写的问题,同时也可以解决高并发读的问题
.
.
分片集群特征
-
集群中有多个master,每个master保存不同数据
-
每个master都可以由多个slave节点
-
master之间通过ping监测彼此监控状态,多个master认为某个master主观下线则会将该master变为客观下线,然后从slave中选举新的master, master选举同哨兵模式
-
客户端请求可以访问集群任意节点,最终都会被转发到正确的节点
.
.
如何判断某个key应该存储在哪个实例?
Redis会将16384(0-16383)个插槽(hash slot)分配到不同的master实例,存储时会根据key的有效部分计算插槽值,根据插槽值将其存储到相应的实例
key的插槽值计算法方式:是利用CRC16算法得到一个hash值,然后对16384取余,得到的结果就是slot值
key的有效部分有两种情况:
-
key中包含"{}",且"{}"中至少包含1个字符,"{}"中的部分就是有效部分
-
key中不包含"{}",整个key就是有效部分
.
.
分片集群搭建
1. 创建6个文件夹
2. 复制redis.conf文件到文件夹目录
3. 修改配置文件内容,将端口和目录分别修改为各实例的端口和目录如下:
# 端口号
port 7001
# 开启集群功能
cluster-enabled yes
# 指定集群配置文件名称,redis自己会创建该文件并维护其内容,不需要我们创建
cluster-config-file /home/s7001/nodes.conf
# 节点心跳超时时间
cluster-node-timeout 5000
# 持久化文件存储目录
dir /home/s7001
# 绑定地址
bind 0.0.0.0
# 守护进程,让redis后台运行
daemonize yes
# 日志,因其后台运行所以记录下日志
logfile /home/s7001/run.log
# 实列的ip
replica-announce-ip 192.168.128.128
# 取消保护模式,
protected-mode no
# 数据库数量,默认是16,我们只需要1个就够了
databases 1
4. 启动所有实例
一个命令启动所有实例,s7001 s7002等参数会替换{}/redis.conf中前面的{},实际执行的命令相当于redis-server s7002/redis.conf
printf '%s\n' s7001 s7002 s7003 s8001 s8002 s8003 | xargs -I{} -t redis-server {}/redis.conf
5. 查看启动状态
执行命令: ps ax|grep redis
6. 创建集群
注:我们使用的Redis版本是6.0.16
执行命令: redis-cli --cluster create --cluster-replicas 1 192.168.128.128:7001 192.168.128.128:7002 192.168.128.128:7003 192.168.128.128:8001 192.168.128.128:8002 192.168.128.128:8003
解读:
redis-cli --cluster: 代表集群操作命令
create: 代表创建集群
--replicas 1:指定集群中每个master字节点个数为1, 1后面的节点前面的3个是master节点,后面的3个事slave节点, slave随机分配到不同的master
7. 连接到集群
执行命令:redis-cli -c -p 7001
连接到集群之后就可以执行set,get等命令,可以看到key指存储到哪个master和key的插槽指
注:-c不能少, 端口可以是集群中任意的
8. 查看节点信息
执行命令: redis-cli -p cluster nodes
或者连接上集群后执行cluster nodes
.
.
添加和删除节点
添加节点
执行命令:redis-cli --cluster add-node 192.168.128.128:7004 192.168.128.128:7001
new_host:new_port 新节点Ip和端口
existing_host:existing_port 已经存在的集群中的节点ip和端口,标识着将新节点添加到哪个集群中
--cluster-slave 缺省表示新增节点是master,否则为slave
--cluster-master-id master节点Id表示新增的slave归属于哪个master
注:新增的master节点需要为其分配slot值
分配slot值
-
启动新增实例
redis-server s7004/redis.config -
将实例添加到集群
redis-cli --cluster add-node 192.168.128.128:7004 192.168.128.128:7001 -
执行命令,任意一个实例即可
redis-cli --cluster reshard 192.168.128.128:7001
插槽0-3000的数据会转移到7004实例
删除节点:
执行命令: redis-cli --cluster del-node 192.168.128.128:7001 b9fdb1cebc54dbf5afdff5e5042dfe0d6b15e881
host:prot 要删除节点的ip和端口号
node_id 要删除节点的id,通过cluster nodes命令查看
.
.
故障转移
当集群中某个master宕机后会发生什么呢?
-
首先该实例与其他master实例失去连接
-
被认定为疑似宕机
-
最后确定下线
-
自动提升一个slave为新的master
.
.
手动数据迁移
-
连接到slave节点,
-
执行命令 cluster failover
可以看出8001变成了master,而原来的master7001变成了8001的slave
cluster failover有两个参数:
-
缺省:默认流程如下图
-
force: 省略了offset一致性校验
-
takeover: 直接执行第5步,忽略数据一致性,忽略master状态和其他master的意见
.
.
代码实现:
- 在pom文件中引入redis的starter依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
- 在application.yml中添加配置
spring:
redis:
cluster:
nodes:
- 192.168.128.128:7001
- 192.168.128.128:7002
- 192.168.128.128:7003
- 192.168.128.128:8001
- 192.168.128.128:8002
- 192.168.128.128:8003
logging:
level:
io.lettuce.core: debug
pattern:
dateformat: MM-dd HH:mm:ss:SSS
- 配置读写分离
配置类中添加下面Bean
@Bean
public LettuceClientConfigurationBuilderCustomizer clientConfigurationBuilderCustomizer(){
return clientConfigurationBuilder -> clientConfigurationBuilder.readFrom(ReadFrom.REPLICA_PREFERRED);
}
ReadFrom是配置redis的读取策略,是一个枚举,包括下面选择:
MASTER:从主节点读取
MASTER_PREFERRED:优先从master节点读取,master不可用才读取slave
REPLICA:从slave读取
REPLICA_PREFERRED:优先从slave读取,所有的slave都不可用才从master读取
- 自行添加get/set方法测试,并查看日志
可以参考上一篇末尾添加set和get接口用来测试 https://www.cnblogs.com/big-strong-yu/p/17037543.html