Redis 分片集群

Redis 分片集群_第1张图片

目录

​编辑一、搭建分片集群

1、集群结构

​编辑 2、准备实例和配置

3、启动

4、创建集群

二、散列插槽

 三、集群伸缩

四、故障转移

1、自动故障转移

2、手动故障转移

五、RedisTemplate 访问分片集群


一、搭建分片集群

1、集群结构

主从和哨兵可以解决高可用、高并发读的问题。但是依然有两个问题没有解决:

1、海量数据存储问题

2、高并发写的问题

使用分片集群可以解决上述问题,分片集群特征:

1、集群中有多个master,每个master保存不同数据

2、每个master都可以有多个slave节点

3、master之间通过ping监测彼此健康状态

4、客户端请求可以访问集群任意节点,最终都会被转发到正确节点 

Redis 分片集群_第2张图片

这里我们会在同一台虚拟机中开启6个redis实例,模拟分片集群,信息如下:

Redis 分片集群_第3张图片 2、准备实例和配置

先删除之前的 7001、7002、7003 这几个目录,重新创建7001、7002、7003、8001、8002、8003 目录

# 进入/tmp目录
cd /tmp
# 删除旧的,避免配置干扰
rm -rf 7001 7002 7003
# 创建目录
mkdir 7001 7002 7003 8001 8002 8003

在 /tmp 下准备一个新的 redis.conf 文件,内容如下:

port 6379
# 开启集群功能
cluster-enabled yes
# 集群的配置文件名称,不需要我们创建,由redis自己维护
cluster-config-file /tmp/6379/nodes.conf
# 节点心跳失败的超时时间
cluster-node-timeout 5000
# 持久化文件存放目录
dir /tmp/6379
# 绑定地址
bind 0.0.0.0
# 让redis后台运行
daemonize yes
# 注册的实例ip
replica-announce-ip 111.229.153.16
# 保护模式
protected-mode no
# 数据库数量
databases 1
# 日志
logfile /tmp/6379/run.log

将这个文件拷贝到每个目录下:

# 进入/tmp目录
cd /tmp
# 执行拷贝
echo 7001 7002 7003 8001 8002 8003 | xargs -t -n 1 cp redis.conf

修改每个目录下的redis.conf,将其中的6379修改为与所在目录一致:

# 进入/tmp目录
cd /tmp
# 修改配置文件
printf '%s\n' 7001 7002 7003 8001 8002 8003 | xargs -I{} -t sed -i 's/6379/{}/g' {}/redis.conf

3、启动

因为已经配置了后台启动模式,所以可以直接启动服务:

# 进入/tmp目录
cd /tmp
# 一键启动所有服务
printf '%s\n' 7001 7002 7003 8001 8002 8003 | xargs -I{} -t redis-server {}/redis.conf

通过ps查看状态:

ps -ef | grep redis

如果要关闭所有进程,可以执行命令:

ps -ef | grep redis | awk '{print $2}' | xargs kill

4、创建集群

我使用的是Redis6.2版本,集群管理以及集成到了redis-cli中,格式如下:

/usr/redis/bin/redis-cli --cluster create --cluster-replicas 1 111.229.153.16:7001 111.229.153.16:7002 111.229.153.16:7003 111.229.153.16:8001 111.229.153.16:8002 111.229.153.16:8003

命令说明:

 输入 yes 之后,集群开始创建

Redis 分片集群_第4张图片


二、散列插槽

Redis会把每一个master节点映射到0~16383共16384个插槽(hash slot)上,查看集群信息时就能看到:

Redis 分片集群_第5张图片

那么为什么要做这样一个插槽呢?

假设现在,我们要 set num 123 那么这个 num 应该存储在哪个 master 上呢? ,假设我们将其存储到 7001 上,那么到时候我们找的时候又怎么知道它存储在 7001 上呢?

插槽就是用来解决这个问题的

数据key不是与节点绑定,而是与插槽绑定。redis 会根据 key 的有效部分计算插槽值,分两种情况:

1、key中包含"{}",且“{}”中至少包含1个字符,“{}”中的部分是有效部分

2、key中不包含“{}”,整个key都是有效部分

例如:key是num,那么就根据num计算,如果是{itcast}num,则根据itcast计算。计算方式是利用CRC16算法得到一个hash值,然后对16384取余,得到的结果就是slot值。

为什么我们的 key 要去和插槽绑定,而不是和节点绑定呢?

这是因为我们 redis 的主节点是可能出现宕机等情况的,如果一个节点删除了或者宕机了,那么上面的数据也就会丢失,而如果数据是和插槽绑定,当节点宕机时,我们可以将这个节点对应的插槽转移到活着的节点,集群扩容时,我们也可以将插槽进行转移,这样数据跟着插槽走,就永远都能找到数据所在的位置了

key 和插槽绑定的体现:

Redis 分片集群_第6张图片

总结:

Redis如何判断某个key应该在哪个实例?

1、将16384个插槽分配到不同的实例

2、根据key的有效部分计算哈希值,对16384取余

3、余数作为插槽,寻找插槽所在实例即可

如何将同一类数据固定的保存在同一个Redis实例?

这一类数据使用相同的有效部分,例如 key 都以 {typeId} 为前缀


 三、集群伸缩

redis-cli --cluster提供了很多操作集群的命令,可以通过下面方式查看:

redis-cli --cluster help

比如,添加节点的命令:

add-node

Redis 分片集群_第7张图片

我们可以看到,添加节点的时候需要几个参数:新节点的端口和 IP,已经存在的主机的端口和 IP

那么为什么我们添加新节点还要知道旧节点的 IP 和端口呢?

因为当你向集群中添加节点,需要通知集群中的每个角色,那么就得先连上集群,提供了已经存在的主机的端口和 IP,就能联系上集群,从而把新节点的信息通知给每一个节点


四、故障转移

1、自动故障转移

当集群中有一个 master 宕机会发生什么呢?

1、首先是该实例与其它实例失去连接

2、然后是疑似宕机:

3、最后是确定下线,自动提升一个slave为新的master:

2、手动故障转移

利用 cluster failover 命令可以手动让集群中的某个 master 宕机,切换到执行 cluster failover 命令的这个 slave 节点,实现无感知的数据迁移。其流程如下:

Redis 分片集群_第8张图片

再执行命令的那一刻,slave 会向 master 发送一个消息,告诉它 当前这个 slave 将要替换它,为了避免消息的丢失,master 就会拒绝客户端的一切请求

此时 master 会返回当前的 offset 给 slave ,如果二者 offset 不一致,就进行同步,同步完成之后,slave 与 master 数据就完全一致了。 

slave 与 master 数据完全一致之后就可以进行故障转移,slave 标记自己成 master 并广播故障转移的结果,master 受到广播后,就转为 slave

手动的 failover 支持三种不同模式:

缺省:默认的流程,如图1~6歩

force:省略了对offset的一致性校验

takeover:直接执行第5歩,忽略数据一致性、忽略master状态和其它master的意见


五、RedisTemplate 访问分片集群

RedisTemplate 底层同样基于 lettuce 实现了分片集群的支持,而使用的步骤与哨兵模式基本一致:

1、引入 redis 的 starter 依赖

2、配置分片集群地址

3、配置读写分离

与哨兵模式相比,其中只有分片集群的配置方式略有差异,如下:

Redis 分片集群_第9张图片

你可能感兴趣的:(Redis,redis,数据库,缓存,后端)