Redis-集群与哨兵 | 青训营

113 阅读9分钟

redis-集群

简介

  • Redis集群是Redis提供的分布式数据库方案,集群通过分片来进行数据共享,并提供复制和故障转移功能
  • 集群就是使用网络将若干台计算机联通起来,并提供统一的管理方式,使其对外呈现单机的服务效果

作用

  • 分散单台服务器的访问压力,实现负载均衡
  • 分散单台服务器的存储压力,实现可扩展性
  • 降低单台服务器宕机带来的业务灾难

集群结构设计

  • 数据存储设计

    • redis的每个节点,都有一个槽(slot),取值范围016383,一共16384个槽,每台主机保存一部分。每个key都会对应到编号为016383的其中一个槽,通过这个槽再去找对应的节点,进行存取操作。
    • Redis集群,要保证16384个槽对应的node都正常工作,如果某个node发生故障,那它负责的slots也就失效,整个集群将不能工作。
    • 官方推荐的方案是将node配置成主从结构,即一个master主节点,挂n个slave从节点。这时,如果主节点失效,Redis Cluster会根据选举算法从slave节点中选择一个上升为主节点,整个集群继续对外提供服务,Redis Cluster本身提供了故障转移容错的能力。
    • 集群模式节点最小配置6个节点(三主三从),其中主节点提供读写操作,从节点作为备用节点,不提供请求,只作为故障转移使用。

集群结构搭建

  • 搭建方式

    • 配置服务器(三主三从)
    • 建立通信(Meet)
    • 分槽(Slot)
    • 搭建主从(master-slave)
  • 工具安装(批处理)

    cluster常见指令
    • Cluster配置

      • 添加节点

        cluster-enabled yes|no
        
      • cluster配置文件名,该文件属于自动生成,仅用于快速查找文件并查询文件内容

        cluster-config-file <filename>
        
      • 节点服务响应超时时间,用于判定该节点是否下线或切换为从节点

        cluster-node-timeout <milliseconds>
        
      • master连接的slave最小数量

        cluster-migration-barrier <count>
        
    • Cluster节点操作命令

      • 查看集群节点信息

        cluster nodes
        
      • 进入一个从节点 redis,切换其主节点

        cluster replicate <master-id>
        
      • 发现一个新节点,新增主节点

        cluster meet ip:port
        
      • 忽略一个没有solt的节点

        cluster forget <id>
        
      • 手动故障转移

        cluster failover
        
    • redis-trib命令

      • 添加节点

        redis-trib.rb add-node
        
      • 删除节点

        redis-trib.rb del-node
        
      • 重新分片

        redis-trib.rb reshard
        

redis-哨兵

简介

哨兵(sentinel) 是一个分布式系统,用于对主从结构中的每台服务器进行监控,当出现故障时通过投票机制选择新的master并将所有slave连接到新的master。

作用

  • 监控

    • 不断的检查master和slave是否正常运行。master存活检测、master与slave运行情况检测
  • 通知

    • 当被监控的服务器出现问题时,向其他(哨兵间,客户端)发送通知。
  • 自动故障转移

    • 断开master与slave连接,选取一个slave作为master,将其他slave连接到新的master,并告知客户端新的服务器地址

启动并初始化哨兵

一、结构配置

  • ① 配置三个哨兵(26379、26380、26381)
  • ② 配置一个master(6379)和两个slave(6380和6381)

二、启动哨兵

命令:redis-sentinel /path/yo/your/sentinel.confredis-server sentinel.conf --sentinel

当一个Sentinel启动时,需要执行以下步骤

  • 初始化服务器。
  • 将普通Redis服务器使用的代码替换成Sentinel专用代码。
  • 初始化Sentinel状态。
  • 根据给定的配置文件,初始化Sentinel的监视主服务器列表。
  • 创建连向主服务器的网络连接。

三、工作原理

① 监控
  • 获取各个sentinel的状态(是否在线)

  • 获取master的状态

    • master属性

      • runid
      • role:master
    • 各个slave的详细信息

  • 获取所有slave的状态(根据master中的slave信息)

    • slave属性

      • runid
      • role:slave
      • master_host、master_port
      • offset

② 通知阶段
  • 在默认情况下,Sentinel 会以每两秒一次的频率, 通过命令连接向所有被监视的主服务 器和从服务器发送以下格式的命令: PUBLISH __sentine1__ :he11o "<s_ ip>,<s_ port>,<s_ runid>,<s_ epoch>,<m_ name>, <m_ip>,<m_ port>, <m_ epoch>"
  • 当Sentinel与一个主服务器或者从服务器建立起订阅连接之后,Sentinel 就会通过订阅连接,向服务器发送以下命令: SUBSCRIBE __sentinel__ :hello Sentinel对__ sentinel__ :hello 频道的订阅会一直持续到Sentinel与服务器的连接断开为止。这也就是说,对于每个与Sentinel连接的服务器,Sentinel 既通过命令连接向服务器的___ sentinel__ :hello频道发送信息,又通过订阅连接从服务器的__ sentinel___ :hello 频道接收信息。
③ 故障转移阶段
  • 主观下线

    • 在默认情况下,Sentinel 会以每秒一次的频率向所有与它创建了命令连接的实例( 主服务器、从服务器、其他Sentinel在内)发送PING命令,并通过实例返回的PING 回复来判断实例是否在线。
    • Sentinel配置文件中的down-after-milliseconds选项指定了Sentinel 判断实例进人主观下线所需的时间长度:如果一个实例在down-after-milliseconds毫秒内,连续向Sentinel 返回无效回复,那么Sentinel会修改这个实例所对应的实例结构,在结构的flags属性中打开SRI_ S_DOWN 标识,以此来表示这个实例已经进人主观下线状态。
  • 客观下线

    • 当Sentinel将-一个 主服务器判断为主观下线之后,为了确认这个主服务器是否真的下线了,它会向同样监视这一- 主服务器的其他Sentinel进行询问,看它们是否也认为主服务器已经进入了下线状态(可以是主观下线或者客观下线)。当Sentinel从其他Sentinel 那里接收到足够数量的已下线判断之后,Sentinel 就会将从服务器判定为客观下线,并对主服务器执行故障转移操作。
    • Sentinel使用:SENTINEL is-master-down-by-addr <ip> <port> <current_ epoch> <runid> 命令询问其他Sentinel是否同意主服务器已下线
  • 选举领头Sentinel

    当一个主服务器被判断为客观下线时,监视这个下线主服务器的各个Sentinel 会进行协商,选举出一个领头Sentinel,并由领头Sentinel对下线主服务器执行故障转移操作。以下是Redis选举领头Sentinel的规则和方法:

    • 所有在线的Sentinel 都有被选为领头Sentinel的资格,换句话说,监视同一个主服 务器的多个在线Sentinel中的任意一 个都有可能成为领头Sentinel。
    • 每次进行领头Sentinel选举之后,不论选举是否成功,所有Sentinel的配置纪元(configuration epoch)的值都会自增一次。 配置纪元实际上就是一个计数器, 并没有 什么特别的。
    • 在一个配置纪元里面,所有Sentinel都有一次将某个Sentinel设置为局部领头Sentinel的机会,并且局部领头一旦设置,在这个配置纪元里面就不能再更改。口每个发现主服务器进人客观下线的Sentinel都会要求其他Sentinel将自已设置为局部领头Sentinel。
    • 当一个Sentinel (源Sentinel)向另一个Sentinel (目标Sentinel)发送SENTINEL is-master-down-by-addr命令,并且命令中的runid参数不是*符号而是源 Sentinel的运行ID时,这表示源Sentinel要求目标Sentinel将前者设置为后者的局 部领头Sentinel。
    • Sentinel设置局部领头Sentinel的规则是先到先得:最先向目标Sentinel发送设置要 求的源Sentinel将成为目标Sentinel的局部领头Sentinel,而之后接收到的所有设置 要求都会被目标Sentinel拒绝。
    • 目标Sentinel在接收到SENTINEL is-master-down-by-addr 命令之后,将向源Sentinel返回一条命令回复,回复中的leader_ runid 参数和leader_ epoch参数分别记录了目标Sentinel的局部领头Sentinel的运行ID和配置纪元。
    • 源Sentinel在接收到目标Sentinel返回的命令回复之后,会检查回复中leader_epoch参数的值和自己的配置纪元是否相同,如果相同的话,那么源Sentinel 继续取出回复中的leader_ runid 参数,如果leader_ runid 参数的值和源Sentinel的运行ID一致,那么表示目标Sentinel将源Sentinel设置成了局部领头Sentinel。
    • 如果有某个Sentinel被半数以上的Sentinel设置成了局部领头Sentinel,那么这个Sentinel成为领头Sentinel。举个例子,在一个由10 个Sentinel组成的Sentinel 系统里面,只要有大于等于10/2+1=6个Sentinel将某个Sentinel设置为局部领头Sentinel,那么被设置的那个Sentinel就会成为领头Sentinel。
    • 因为领头Sentinel的产生需要半数以上Sentinel的支持,并且每个Sentinel在每个配置纪元里面只能设置一次局部领头Sentinel,所以在一个配置纪元里面,只会出现一个领头Sentinel。
    • 如果在给定时限内,没有一个Sentinel被选举为领头Sentinel,那么各个Sentinel将 在一段时间之后再次进行选举,直到选出领头Sentinel为止。
  • 选出新的主服务器 故障转移操作第一步要做的就是在已下线主服务器属下的所有从服务器中,挑选出一个状态良好、数据完整的从服务器,然后向这个从服务器发送SLAVEOF no one命令,将这个从服务器转换为主服务器。

    • 删除列表中所有处于下线或者断线状态的从服务器。
    • 删除列表中所有最近五秒内没有回复过领头Sentinel的INFO命令的从服务器。
    • 删除所有与已下线主服务器连接断开超过down-after-milliseconds * 10毫秒的从服务器: down-after-milliseconds选项指定了判断主服务器下线所需的 时间,而删除断开时长超过down-after-milliseconds * 10毫秒的从服务器,则 可以保证列表中剩余的从服务器都没有过早地与主服务器断开连接,换句话说,列表中 剩余的从服务器保存的数据都是比较新的。
    • 领头Sentinel将根据从服务器的优先级,对列表中剩余的从服务器进行排序,并选出其中优先级最高的从服务器。
    • 如果有多个具有相同最高优先级的从服务器,那么领头Sentinel将按照从服务器的复制偏移量,对具有相同最高优先级的所有从服务器进行排序,并选出其中偏移量最大的从服务器(复制偏移量最大的从服务器就是保存着最新数据的从服务器)。
    • 如果有多个优先级最高、复制偏移量最大的从服务器,那么领头Sentinel将按照运行ID对这些从服务器进行排序,并选出其中运行ID最小的从服务器。
  • 向其他slave发送slaveof 新masterIP端口