• Redis分布式缓存(四)| 分片集群搭建、散列插槽、集群伸缩、故障转移、与SpringBoot集成分片集群



    接上一篇:Redis分布式缓存(三)| 哨兵集群原理、哨兵集群搭建、集群故障恢复、与SpringBoot集成


    Redis分片集群

    1.搭建分片集群

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

    • 海量数据存储问题
    • 高并发写的问题

    使用分片集群可以解决上述问题,如图:
    在这里插入图片描述

    分片集群特征:

    • 集群中有多个master,每个master保存不同数据
    • 每个master都可以有多个slave节点
    • master之间通过ping监测彼此健康状态
    • 客户端请求可以访问集群任意节点,最终都会被转发到正确节点

    1.1.集群结构

    分片集群需要的节点数量较多,这里我们搭建一个最小的分片集群,包含3个master节点,每个master包含一个slave节点,结构如下:
    在这里插入图片描述

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

    IPPORT角色
    192.168.188.1287001master
    192.168.188.1287002master
    192.168.188.1287003master
    192.168.188.1288001slave
    192.168.188.1288002slave
    192.168.188.1288003slave

    1.2.准备实例和配置

    删除之前的700170027003这几个目录,重新创建出700170027003800180028003目录:

    进入/tmp目录

    cd /tmp
    
    • 1

    删除旧的,避免配置干扰

    rm -rf 7001 7002 7003
    
    • 1

    创建目录

    mkdir 7001 7002 7003 8001 8002 8003
    
    • 1

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

    touch /tmp/redis.conf
    
    • 1

    将以下内容复制到文件中保存

    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 192.168.188.128
    # 保护模式
    protected-mode no
    # 数据库数量
    databases 1
    # 日志
    logfile /tmp/6379/run.log
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

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

    进入/tmp目录

    cd /tmp
    
    • 1

    执行拷贝

    echo 7001 7002 7003 8001 8002 8003 | xargs -t -n 1 cp redis.conf
    
    • 1

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

    进入/tmp目录

    cd /tmp
    
    • 1

    修改配置文件

    printf '%s\n' 7001 7002 7003 8001 8002 8003 | xargs -I{} -t sed -i 's/6379/{}/g' {}/redis.conf
    
    • 1

    1.3.启动服务

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

    进入/tmp目录

    cd /tmp
    
    • 1

    一键启动所有服务

    printf '%s\n' 7001 7002 7003 8001 8002 8003 | xargs -I{} -t redis-server {}/redis.conf
    
    • 1

    通过ps查看状态:

    ps -ef | grep redis
    
    • 1

    发现服务都已经正常启动:

    在这里插入图片描述


    1.4.停止服务

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

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

    或者(推荐这种方式):

    printf '%s\n' 7001 7002 7003 8001 8002 8003 | xargs -I{} -t redis-cli -p {} shutdown
    
    • 1

    1.5.创建集群

    虽然服务启动了,但是目前每个服务之间都是独立的,没有任何关联。

    我们需要执行命令来创建集群,在Redis5.0之前创建集群比较麻烦,5.0之后集群管理命令都集成到了redis-cli中。

    1)Redis5.0之前

    Redis5.0之前集群命令都是用redis安装包下的src/redis-trib.rb来实现的。因为redis-trib.rb是有ruby语言编写的所以需要安装ruby环境。

    安装依赖

    yum -y install zlib ruby rubygems
    
    • 1
    gem install redis
    
    • 1

    然后通过命令来管理集群:

    进入redis的src目录

    cd /tmp/redis-6.2.4/src
    
    • 1

    创建集群

    ./redis-trib.rb create --replicas 1 192.168.188.128:7001 192.168.188.128:7002 192.168.188.128:7003 192.168.188.128:8001 192.168.188.128:8002 192.168.188.128:8003
    
    • 1

    2)Redis5.0以后

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

    redis-cli --cluster create --cluster-replicas 1 192.168.188.128:7001 192.168.188.128:7002 192.168.188.128:7003 192.168.188.128:8001 192.168.188.128:8002 192.168.188.128:8003
    
    • 1

    命令说明:

    • redis-cli --cluster或者./redis-trib.rb:代表集群操作命令
    • create:代表是创建集群
    • --replicas 1或者--cluster-replicas 1 :指定集群中每个master的副本个数为1,此时节点总数 ÷ (replicas + 1) 得到的就是master的数量。因此节点列表中的前n个就是master,其它节点都是slave节点,随机分配到不同master

    运行后的样子:
    在这里插入图片描述

    这里输入yes,则集群开始创建:

    在这里插入图片描述

    通过命令可以查看集群状态:

    redis-cli -p 7001 cluster nodes
    
    • 1

    在这里插入图片描述


    1.6.创建集群报错

    因为我这里是第二次创建了,所有出现了这个问题

    如果出现报错,则将每个节点下对应的文件夹下的aof、rdb、nodes.conf本地备份文件删除

    node节点文件:nodes.conf,是redis.conf里面cluster-config-file熟悉

    在这里插入图片描述

    删除后执行1.5步的创建集群命令,还是不行,先看看是否有遗漏的文件没有删除;如果没有,建议从1.2步重新开始。


    1.7.测试集群连接

    尝试连接7001节点,存储一个数据:

    # 连接
    redis-cli -p 7001
    # 存储数据
    set num 123
    # 读取数据
    get num
    # 再次存储
    set a 1
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    结果发现set a 1添加不了:

    在这里插入图片描述

    集群操作时,需要给redis-cli加上-c参数才可以:

    redis-cli -c -p 7001
    
    • 1

    这次可以了:

    在这里插入图片描述


    2.散列插槽

    2.1.插槽原理

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

    在这里插入图片描述

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

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

    2.2.插槽切换测试

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

    注意:这里连接redis客户端的命令多了一个-c

    redis-cli -c -p 7001
    
    • 1

    在这里插入图片描述

    如图,在7001这个节点执行set a 1时,对ahash运算,对16384取余,得到的结果是15495,因此要存储到103节点。

    到了7003后,执行get num时,对numhash运算,对16384取余,得到的结果是2765,因此需要切换到7001节点


    2.3.小结

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

    • 16384个插槽分配到不同的实例
    • 根据key的有效部分计算哈希值,对16384取余
    • 余数作为插槽,寻找插槽所在实例即可

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

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

    3.集群伸缩

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

    redis-cli --cluster help
    
    • 1

    在这里插入图片描述

    比如,添加节点的命令:

    在这里插入图片描述


    3.1.向集群中添加一个节点分析

    需求:向集群中添加一个新的master节点,并向其中存储 num = 10

    • 启动一个新的redis实例,端口为7004
    • 添加7004到之前的集群,并作为一个master节点
    • 7004节点分配插槽,使得num这个key可以存储到7004实例

    这里需要两个新的功能:

    • 添加一个节点到集群中
    • 将部分插槽分配到新插槽

    3.2.创建新的redis实例

    进入/tmp目录

    cd /tmp
    
    • 1

    创建一个文件夹:

    mkdir 7004
    
    • 1

    拷贝配置文件:

    cp redis.conf /tmp/7004
    
    • 1

    修改配置文件:

    sed -i -e 's/6379/7004/g' 7004/redis.conf
    
    • 1

    启动

    redis-server 7004/redis.conf
    
    • 1

    查看是否启动

    ps -ef | grep redis
    
    • 1

    在这里插入图片描述


    3.3.添加新节点到redis

    添加节点的语法如下:

    在这里插入图片描述

    执行添加节点命令:

    redis-cli --cluster add-node  192.168.188.128:7004 192.168.188.128:7001
    
    • 1

    通过命令查看集群状态:

    redis-cli -p 7001 cluster nodes
    
    • 1

    如图,7004加入了集群,并且默认是一个master节点:

    在这里插入图片描述

    但是,可以看到7004节点的插槽数量为0,因此没有任何数据可以存储到7004


    3.4.转移插槽

    我们要将num存储到7004节点,因此需要先看看num的插槽是多少:

    redis-cli -c -p 7001
    
    • 1

    在这里插入图片描述

    如上图所示,num的插槽为2765.

    我们可以将0~3000的插槽从7001转移到7004,命令格式如下:

    redis-cli --cluster help
    
    • 1

    在这里插入图片描述

    具体命令如下:

    redis-cli --cluster reshard 192.168.188.128:7001
    
    • 1

    建立连接,得到下面的反馈:

    在这里插入图片描述

    询问要移动多少个插槽,我们计划是3000个:

    新的问题来了:

    在这里插入图片描述

    那个node来接收这些插槽?

    显然是7004,那么7004节点的id是多少呢?可以在当前窗口的上面看到

    在这里插入图片描述

    复制这个id,然后拷贝到刚才的控制台后:

    在这里插入图片描述

    这里询问,你的插槽是从哪里移动过来的?

    • all:代表全部,也就是三个节点各转移一部分
    • 具体的id:目标节点的id
    • done:结束

    这里我们要从7001获取,因此填写7001id

    在这里插入图片描述

    输入7001节点id后,输入done完成插槽转移,这样插槽转移就准备好了:

    在这里插入图片描述

    确认要转移吗?输入yes

    然后,通过命令查看结果:

    redis-cli -p 7001 cluster nodes
    
    • 1

    可以看到,7004已经有3000个插槽了,而7001的插槽减少了3000个:

    在这里插入图片描述

    转移插槽总结:

    先确定转多少个,再输入接收这些插槽的节点ID,再输入转出节点的ID。


    3.5.测试插槽转移

    连接redis集群7001节点

    redis-cli -c -p 7001
    
    • 1

    可以看到num的插槽2765已经到7004节点上了

    在这里插入图片描述


    3.6.从集群中删除一个节点

    假如我要把7004节点从集群中删除,该怎么做?

    查看帮助命令:

    redis-cli --cluster help
    
    • 1

    在这里插入图片描述

    可以看到直接使用命令把地址和端口,以及节点ID拼起来执行就行了?我们试一下

    查看集群状态

    redis-cli -p 7001 cluster nodes
    
    • 1

    删除节点

    redis-cli --cluster del-node 192.168.188.128:7004 d4667191436da278c9888941c839c4e0f2b6d672
    
    • 1

    在这里插入图片描述

    发现报错了!为啥?

    [ERR] Node 192.168.188.128:7004 is not empty! Reshard data away and try again.

    各位还记得上一步我们添加节点之后,已经给7004这个节点分配了3000个插槽,如果直接删除,就会像上面一样报错,意思是7004这个节点不是空的,需要你重新分配插槽,把7004节点上的插槽分配到其他master节点上。


    再来操作一下

    我们先把7004节点上的3000个插槽转移回7001节点

    redis-cli --cluster reshard 192.168.188.128:7004
    
    • 1

    在这里插入图片描述

    再次确认:

    在这里插入图片描述

    然后,通过命令查看结果:

    redis-cli -p 7001 cluster nodes
    
    • 1

    可以看到7004节点的插槽已经回到7001节点了

    在这里插入图片描述

    再次进行节点删除:

    redis-cli --cluster del-node 192.168.188.128:7004 d4667191436da278c9888941c839c4e0f2b6d672
    
    • 1

    可以看到已经可以删除成功了

    在这里插入图片描述

    查看集群状态,可以看到已经没有7004节点了

    redis-cli -p 7001 cluster nodes
    
    • 1

    在这里插入图片描述

    删除插槽总结:

    先确定需要删除节点是否有插槽,没有则可以直接使用删除命令,如果有插槽,先将插槽转移到其他节点,再进行删除。


    4.故障转移

    4.1.自动故障转移

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

    使用监控命令查看集群状态:

    watch redis-cli -p 7001 cluster nodes
    
    • 1

    集群初始状态是这样的:

    在这里插入图片描述

    其中700170027003都是master,我们计划让7002宕机。

    新开一个ssh窗口,直接停止一个redis实例,例如7002:

    redis-cli -p 7002 shutdown
    
    • 1

    1)首先是该实例与其它实例失去连接,疑似宕机:
    在这里插入图片描述


    2)最后是确定下线,自动提升一个slave为新的master,这里是8002节点升为master

    在这里插入图片描述


    3)当7002再次启动,就会变为一个slave节点了:

    在新窗口执行7002节点启动

    redis-server /tmp/7002/redis.conf
    
    • 1

    在监控窗口查看集群状态变化

    在这里插入图片描述


    4.2.手动故障转移

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

    在这里插入图片描述

    这种failover命令可以指定三种模式:

    • 缺省:默认的流程,如图1~6歩
    • force:强制,省略了对offset的一致性校验
    • takeover:直接执行第5歩,忽略数据一致性、忽略master状态和其它master的意见

    4.2.1.案例需求:

    7002这个slave节点执行手动故障转移,重新夺回master地位

    步骤如下:

    1)利用redis-cli连接7002这个节点

    redis-cli -p 7002
    
    • 1

    2)执行cluster failover命令

    cluster failover
    
    • 1

    如图:

    在这里插入图片描述

    效果:可以看到7002节点从slave节点提升为master节点了,而8002降级为slave节点

    redis-cli -p 7001 cluster nodes
    
    • 1

    在这里插入图片描述


    5.RedisTemplate访问分片集群

    这里跟上一篇的文章衔接,不做过多的代码粘贴了。上一篇:Redis分布式缓存(三)| 哨兵集群原理、哨兵集群搭建、集群故障恢复、与SpringBoot集成

    RedisTemplate底层同样基于lettuce实现了分片集群的支持,而使用的步骤与哨兵模式基本一致:
    1)引入redis的starter依赖
    2)配置分片集群地址
    3)配置读写分离

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

    # 哨兵模式
    #spring:
    #  redis:
    #    sentinel:
    #      master: mymaster # 指定master名称
    #      nodes:  # 指定redis-sentinel集群信息
    #        - 192.168.188.128:27001
    #        - 192.168.188.128:27002
    #        - 192.168.188.128:27003
    
    # 分片集群模式
    spring:
      redis:
        cluster:
          nodes:  # 指定redis分片集群地址
            - 192.168.188.128:7001
            - 192.168.188.128:7002
            - 192.168.188.128:7003
            - 192.168.188.128:8001
            - 192.168.188.128:8002
            - 192.168.188.128:8003
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    大家自行测试,查看idea控制台的日志,可以看到读写分离时会根据key计算插槽的位置,并根据插槽位置找到对应的节点,自动切换到该节点,这里我就不做演示了。


  • 相关阅读:
    Mycat核心教程--Mycat 监控工具【四】
    深度学习如何入门?
    系统升级丨VR会议主动呼叫,开启云洽谈新模式
    汽车MCU虚拟化--对中断虚拟化的思考(1)
    CAPL学习之路-以太网函数
    springboot系列(二十):如何通过redis实现手机号验证码功能 |超级详细,建议收藏
    甲骨文、SUSE 和 CIQ (Rocky Linux )提供Open Enterprise Linux Association (OpenELA)
    小白跟做江科大32单片机之按键控制LED
    网课答案查题公众号新手教程!内附网课题库接口!
    同步篇——事件等待与唤醒
  • 原文地址:https://blog.csdn.net/qq_25112523/article/details/125495914