• 【Redis】10.哨兵模式与分片集群


    1. Redis哨兵模式

    在主从集群模式下,salve节点宕机后可以找master节点同步数据,但是倘若master节点宕机后怎么办?

    Redis提供了哨兵(Sentinel)机制来实现主从集群的自动故障恢复。哨兵的结构和作用如下:

    • 监控:Sentinel 会不断检查您的master和slave是否按预期工作。

      • Sentinel基于心跳机制监测服务状态,每隔1秒向集群的每个实例发送ping命令:

        • 主观下线:如果某sentinel节点发现某实例未在规定时间响应,则认为该实例主观下线
        • 客观下线:若超过指定数量(quorum)的sentinel都认为该实例主观下线,则该实例客观下线。quorum值最好超过Sentinel实例数量的一半。
        • image-20221107153849437
    • 自动故障恢复:如果master故障,Sentinel会将一个slave提升为master。当故障实例恢复后也以新的master为主。

      • 当哨兵监测到master宕机,会自动将slave切换成master,然后通过发布订阅模式通知其他的从服务器,修改配置文件,让它们切换主机。
    • 通知:Sentinel充当Redis客户端的服务发现来源,当集群发生故障转移时,会将最新信息推送给Redis的客户端。

    image-20221107153607526

    并且单个哨兵对Redis服务器进行监控,可能会出现问题,因此可以使用多个哨兵进行监控。各个哨兵之间还会互相监控,这样就形成了多哨兵模式


    1.1 搭建哨兵集群

    这里准备使用三个节点作为Sentinel集群,用来监管之前的Redis主从集群。

    三个sentinel实例信息如下:

    节点IPPORT
    s1192.168.150.10127001
    s2192.168.150.10127002
    s3192.168.150.10127003

    准备一个sentinel.conf的配置文件

    port 27001
    sentinel announce-ip 192.168.150.101
    sentinel monitor mymaster 192.168.150.101 7001 2
    sentinel down-after-milliseconds mymaster 5000
    sentinel failover-timeout mymaster 60000
    dir "/tmp/s1"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • port 27001:是当前sentinel实例的端口
    • sentinel monitor mymaster 192.168.150.101 7001 2:指定主节点信息
      • mymaster:主节点名称,自定义,任意写
      • 192.168.150.101 7001:主节点的ip和端口
      • 2:选举master时的quorum值

    另外两个sentinel也需要准备这个配置文件,只是需要把端口号改了。

    然后启动三个redis实例

    # 第1个
    redis-sentinel s1/sentinel.conf
    # 第2个
    redis-sentinel s2/sentinel.conf
    # 第3个
    redis-sentinel s3/sentinel.conf
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    这样哨兵集群的搭建完成了。

    哨兵启动后只指定了master的地址,要想知道整个集群中完整的拓扑关系怎么做呢?

    哨兵每隔10s就会向每个master节点发送info命令,info命令返回的信息中,包含了主从拓扑关系,其中包括每个slave的地址和端口号。有了这些信息后,哨兵就会记住这些节点的拓扑信息,在后续发生故障时,选择合适的slave节点进行故障恢复。

    那么哨兵之间是怎样通信的呢?

    哨兵之间是通过Redis提供的发布(pub)/订阅(sub)机制完成的。哨兵节点不会直接与其他哨兵节点建立连接,而是首先会和主库建立起连接,然后向一个名为"sentinel:hello"频道发送自己的信息(IP 和端口),其他订阅了该频道的哨兵节点就会获取到该哨兵节点信息,从而哨兵节点之间互知。


    1.2 选举规则与故障转移

    一旦master故障,sentinel就需要在多个salve中选择一个作为新的master,选择规则如下:

    1. 首先判断salve节点与master断开时间长短,如果超过指定值(down-after-milliseconds * 10)则会排除该slave节点
    2. 然后判断slave节点的slave-priority值,越小优先级越高,如果是0则永不参与选举
    3. 如果slave-prority一样,则判断slave节点的offset值,越大说明数据越新,优先级越高
    4. 最后是判断slave节点的运行id大小,越小优先级越高。

    简而言之,就是slave-priority配置 > 数据完整性 > runid较小者进行选择

    选举出新的master之后,就要开始进行故障转移了,步骤如下:

    1. sentinel给备选的slave1节点发送slaveof no one命令,让该节点成为master
    2. sentinel给所有其它slave发送slaveof 192.168.150.101 7002 命令,让这些slave成为新master的从节点,开始从新的master上同步数据。
    3. 最后,sentinel将故障节点标记为slave,当故障节点恢复后会自动成为新的master的slave节点

    image-20221107160000419


    1.3 RedisTemplate的哨兵模式

    在Java中使用哨兵模式,需要以下步骤:

    1. 在pom文件中引入redis的starter依赖:

      
      <dependency>
          <groupId>org.springframework.bootgroupId>
          <artifactId>spring-boot-starter-data-redisartifactId>
      dependency>
      
      • 1
      • 2
      • 3
      • 4
      • 5
    2. 然后在配置文件application.yml中指定sentinel相关信息:

      spring:  
      	redis:    
      		sentinel:      
      			master: mymaster # 指定master名称      
      			nodes: # 指定redis-sentinel集群信息        
      				- 192.168.150.101:27001       
      				- 192.168.150.101:27002       
      				- 192.168.150.101:27003
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
    3. 配置主从读写配置

      @Bean
      public LettuceClientConfigurationBuilderCustomizer clientConfigurationBuilderCustomizer(){
          return clientConfigurationBuilder -> 		clientConfigurationBuilder.readFrom(ReadFrom.REPLICA_PREFERRED);
      }
      
      • 1
      • 2
      • 3
      • 4

    **这里的ReadFrom是配置Redis的读取策略,是一个枚举,**包括下面选择:

    • MASTER:从主节点读取
    • MASTER_PREFERRED:优先从master节点读取,master不可用才读取replica
    • REPLICA:从slave(replica)节点读取
    • REPLICA _PREFERRED:优先从slave(replica)节点读取,所有的slave都不可用才读取master

    这样配置完之后,客户端就能感知到主节点发生改变了。

    那么,主节点发生变化的时候,客户端是如何感知的呢?

    这是基于redis提供的发布(pub)/订阅(sub)机制完成的,客户端可以从哨兵订阅消息,故障转移后,客户端会收到订阅消息。


    2. Redis分片集群

    主从哨兵模式可以更好解决高可用、高并发读的问题。但是面对高并发写与海量数据存储的问题,这种模式依然存在问题

    因此,分片集群模式的出现,就能解决上述出现的问题。

    分片集群特征:

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

    • 每个master都可以有多个slave节点

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

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


    2.1 搭建分片集群

    这里就搭建3个master节点,每个master包含一个salve节点。

    image-20210702164116027

    信息如下:

    IPPORT角色
    192.168.150.1017001master
    192.168.150.1017002master
    192.168.150.1017003master
    192.168.150.1018001slave
    192.168.150.1018002slave
    192.168.150.1018003slave

    准备一个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 192.168.150.101
    # 保护模式,不需要密码就可以进去
    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

    每个实例都修改成自己的端口号,然后启动实例。

    image-20210702174255799

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

    在Redis5.0以后,集群管理已经集成到redis-cli中

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

    命令说明:

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

    这样集群的搭建完成了。


    2.2 散列插槽

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

    image-20210725155820320

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

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

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

    image-20210725155850200

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

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

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

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


    2.3 集群伸缩

    redis-cli --cluster还提供了添加节点的命令。

    image-20210725160448139

    新建一个redis节点7004,执行下面命令

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

    通过命令查看集群状态:

    redis-cli -p 7001 cluster nodes
    
    • 1

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

    image-20210725161007099

    但是此时7004的插槽数为0,任何数据都不可以存储在7004中。

    因此,就需要进行转移插槽的操作了

    假如想要将num存储在7004节点,就要先看看num的插槽是多少了

    image-20210725161241793

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

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

    image-20210725161401925

    建立连接:

    image-20210725161506241

    image-20210725161540841

    这里就是问要移动多少个插槽,这里我想移动3000个

    image-20210725161637152

    这里问的是那个node来接收这些插槽??

    显然是7004节点,可以查看节点的id

    image-20210725161731738

    image-20210725161817642

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

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

    这里可以选择从7001获取,所以填写7001的id

    image-20210725162030478

    填完后,点击done,这样插槽转移就准备好了:

    最后输入yes,就可以了

    再次查看,可以看见插槽分配成功了

    image-20210725162224058


    2.4 故障转移

    对于宕机的master进行故障转移,有以下两种方式:

    • 自动故障转移
    • 手动故障转移

    2.4.1 自动故障转移

    自动故障转移的话,当一个redis宕机

    首先先是疑似宕机

    image-20210725162319490

    然后确认下线,自动升级一个salve为新的master

    image-20210725162408979

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

    image-20210727160803386


    2.4.2 手动故障转移

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

    image-20210725162441407

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

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

    2.5 RedisTemplate访问分片集群

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

    1)引入redis的starter依赖

    2)配置分片集群地址

    3)配置读写分离

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

    spring:
      redis:
        cluster:
          nodes:
            - 192.168.150.101:7001
            - 192.168.150.101:7002
            - 192.168.150.101:7003
            - 192.168.150.101:8001
            - 192.168.150.101:8002
            - 192.168.150.101:8003
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    参考:


  • 相关阅读:
    36 数据增广【李沐动手学深度学习v2课程笔记】
    趣学算法:分治算法
    软件测试 - 项目实战篇
    HTML5+CSS3-HTML5入门
    Degrade is Upgrade: Learning Degradation for Low-light Image Enhancement论文阅读笔记
    [每周一更]-(第73期):介绍容器监控工具-CAdvisor
    【GUI软件】小红书关键词搜索结果批量采集
    华为云云耀云服务器L实例评测|轻量级应用服务器对决:基于 STREAM 深度测评华为云云耀云服务器L实例的内存性能
    12年开发大佬,熬夜4个月整理的SpringBoot实战派,绝对涨薪秘籍
    sqlmap获取目标
  • 原文地址:https://blog.csdn.net/weixin_51146329/article/details/127734966