Redis集群

一、简介

         Redis集群是Redis提供的分布式数据库方案,集群通过分片(sharding)来进行数据共享,并提供复制和故障转移功能。哨兵解决了高可用的问题,而集群就是终极方案,一举解决高可用和分布式问题。

      

  1. 数据分区: 数据分区 (或称数据分片) 是集群最核心的功能。集群将数据分散到多个节点,一方面 突破了 Redis 单机内存大小的限制,存储容量大大增加另一方面 每个主节点都可以对外提供读服务和写服务,大大提高了集群的响应能力

  2. 高可用: 集群支持主从复制和主节点的 自动故障转移 (与哨兵类似),当任一节点发生故障时,集群仍然可以对外提供服务。

二、集群的原理

        Redis集群通过数据分区来实现数据的分布式存储,通过自动故障转移实现高可用。

          集群创建

        数据分区是在集群创建的时候完成的。

     

        设置节点 Redis集群一般由多个节点组成(一个节点就是一个运行在集群模式下的Redis服务器),节点数量至少为6个才能保证组成完整高可用的集群。每个节点需要开启配置cluster-enabled yes,决定是否开启集群模式。

    

 

        节点握手节点握手是指一批运行在集群模式下的节点(一个Redis集群通常由多个节点(node)组成,在刚开始的时候,每个节点都是相互独立的,它们都处于一个只包含自己的集群当中,要组建一个真正可工作的集群,我们          必须将各个独立的节点连接起来,构成一个包含多个节点的集群。)通过Gossip协议彼此通信, 达到感知对方的过程。节点握手是集群彼此通信的第一步,由客户端发起命 令:cluster meet{ip}{port}。握手成功时,node节点就          会将ip和port所指定的节点添加到node节点当前所在的集群中。

  

         分配槽(slot)Redis集群把所有的数据映射到16384个槽中(Redis集群通过分片的方式来保存数据库中的键值对:集群的整个数据库被分为16384个槽(slot),数据库中的每个键都属于这16384个槽的其中一个,集群每个            节点可以处理0个或最多16384个槽。)。每个节点对应若干个槽,只有当节点分配了槽,才能响应和这些槽关联的键命令。通过 cluster addslots命令为节点分配槽。

         故障转移

         Redis集群的故障转移和哨兵的故障转移类似,但是Redis集群中所有的节点都要承担状态维护的任务。

 

 

          故障发现Redis集群内节点通过ping/pong消息实现节点通信,集群中每个节点都会定期向其他节点发送ping消息,接收节点回复pong 消息作为响应。如果在cluster-node-timeout时间内通信一直失败,则发送节点会认为接收节             点存在故障,把接收节点标记为主观下线(pfail 疑似下线)状态。

       

 

        当某个节点判断另一个节点主观下线后,相应的节点状态会跟随消息在集群内传播(集群中的各个节点会通过互相发送消息的方式来交换集群中各个节点的状态信息)。通过Gossip消息传播,集群内节点不断收集到故障节点的          下线报告。当半数以上持有槽的主节点都标记某个节点是主观下线时。触发客观下线流程(已下线)。

 

    

 

          故障恢复

         故障节点变为客观下线后,如果下线节点是持有槽的主节点则需要在它 的从节点中选出一个替换它,从而保证集群的高可用(实现故障转移)。步骤如下:

  1. 复制下线主节点的所有从节点里面,会有一个从节点被选中。
  2. 被选中的从节点会执行SLAVEOF no one命令,成为新的主节点。
  3. 新的主节点会撤销所有对已下线主节点的槽指派,并将这些槽全部指派给自己。
  4. 新的主节点向集群广播一条PONG消息,这条PONG消息可以让集群中的其他节点立即知道这个节点已经由从节点变成了主节点,并且这个主节点已经接管了原本由已下线节点负责处理的槽。
  5. 新的主节点开始接收和自己负责处理的槽有关的命令请求,故障转移完成。

        复制

        Redis集群中的节点分为主节点(master)和从节点(slave),其中主节点用于处理槽,而从节点则用于复制某个主节点,并在被复制的主节点下线时,代替下线主节点继续处理命令请求。向一个节点发送命令:CLUSTER              REPLICATE <node_id>以让接收命令的节点成为node_id所指定节点的从节点,并开始对主节点进行复制:一个节点成为从节点,并开始复制某个主节点这一信息会通过消息发送给集群中的其他节点,最终集群中的所有节点都          会知道某个从节点正在复制某个主节点。

        选举新的主节点

        持有槽的主节点处理故障选举消息。投票过程其实是一个领导者选举的过程,如集群内有N个持有槽的主节 点代表有N张选票。由于在每个配置纪元内持有槽的主节点只能投票给一个 从节点,因此只能有一个从节点获得N/2+1          的选票,保证能够找出唯一的从节点。(与哨兵选举类似)

  三、集群中数据如何分区

       分布式的存储中,要把数据集按照分区规则映射到多个节点,常见的数据分区规则三种:

     

 

 

 

      方案一:节点取余分区

      节点取余分区,非常好理解,使用特定的数据,比如Redis的键,或者用户ID之类,对响应的hash值取余:hash(key)%N,来确定数据映射到哪一个节点上。

      不过该方案最大的问题是,当节点数量变化时,如扩容或收缩节点,数据节点映射关 系需要重新计算,会导致数据的重新迁移。

     

 

 

 

      方案二:一致性哈希分区
      将整个 Hash 值空间组织成一个虚拟的圆环,然后将缓存节点的 IP 地址或者主机名做 Hash 取值后,放置在这个圆环上。当我们需要确定某一个 Key 需 要存取到哪个节点上的时候,先对这个 Key 做同样的 Hash 取值,确定在上的位置,然后按照顺时针方向在环上“行走”,遇到的第一个缓存节点就是要访问的节点。比如说下面 这张图里面,Key 1 和 Key 2 会落入到 Node 1 中,Key 3、Key 4 会落入到 Node 2 中,Key 5 落入到 Node 3 中,Key 6 落入到 Node 4 中。
   

 

 

       

         这种方式相比节点取余最大的好处在于加入和删除节点只影响哈希环中 相邻的节点,对其他节点无影响。

         但它还是存在问题:

  • 缓存节点在圆环上分布不平均,会造成部分缓存节点的压力较大
  • 当某个节点故障时,这个节点所要承担的所有访问都会被顺移到另一个节点上,会对后面这个节点造成力。
         方案三:虚拟槽分区

         这个方案 一致性哈希分区的基础上,引入了 虚拟节点 的概念。Redis 集群使用的便是该方案,其中的虚拟节点称为 槽(slot)。槽是介于数据和实际节点之间的虚拟概念,每个实际节点包含一定数量的槽,每个槽包含哈希值在一定范围内的数据。

    

 

 

        

         在使用了槽的一致性哈希分区中,槽是数据管理和迁移的基本单位。槽解耦了数据和实际节点 之间的关系,增加或删除节点对系统的影响很小。仍以上图为例,系统中有 4 个实际节点,假设为其分配 16 个槽(0-15);

 

  • 槽 0-3 位于 node1;4-7 位于 node2;以此类推....

 

         如果此时删除 node2,只需要将槽 4-7 重新分配即可,例如槽 4-5 分配给 node1,槽 6 分配给 node3,槽 7 分配给 node4,数据在其他节点的分布仍然较为均衡。

 

 

          部署Redis集群至少需要几个物理节点?

         在投票选举的环节,故障主节点也算在投票数内,假设集群内节点规模是3主3从,其中有2 个主节点部署在一台机器上,当这台机器宕机时,由于从节点无法收集到 3/2+1个主节点选票将导致故障转移失败。这个问题也适用于故障发现环节。因此部署集群时所有主节点最少需要部署在3台物理机上才能避免单点问题。

四、集群的伸缩

         Redis集群提供了灵活的节点扩容和收缩方案,可以在不影响集群对外服务的情况下,为集群添加节点进行扩容也可以下线部分节点进行缩容。

    

 

 

          

         其实,集群扩容和缩容的关键点,就在于槽和节点的对应关系,扩容和缩容就是将一部分数据迁移给新节点。

         例如下面一个集群,每个节点对应若干个槽,每个槽对应一定的数据,如果希望加入1个节点希望实现集群扩容时,需要通过相关命令把一部分槽和内容迁移给新节点。

   

         缩容也是类似,先把槽和数据迁移到其它节点,再把对应的节点下线。

 

posted @ 2022-06-14 14:44  呆Finn  阅读(233)  评论(0编辑  收藏  举报