Redis——第16章:哨兵模式

Redis Sentinel是一个高可用性解决方案,监控并自动故障切换主从服务器。Sentinel启动时会根据配置文件初始化主从服务器信息,通过INFO命令交互获取服务器状态。当检测到主观下线后, Sentinel通过多数投票进行客观下线判断,采用Raft算法选举领头哨兵,执行故障修复,选择新的主服务器并更新从服务器的复制关系。
摘要由CSDN通过智能技术生成
  • 概述
  • 启动和初始化
    • conf配置和启动命令
    • 启动流程
      • 不执行AOD和RDB,Sentinel专用代码
      • sentinelState结构体
      • sentinelRedisInstance结构体,记录监视的主从服务器
      • 订阅 + 命令连接
  • Sentinel与主从服务器的交互
    • Sentinel如何初始化 主服务器 信息
    • Sentinel如何初始化 从服务器 信息
    • Sentinel向 订阅频道发送信息
    • Sentinel如何初始化 其他Sentinel 信息
    • 总结
  • 下线判断和故障修复
    • 下线判断
      • 主观检测
      • 客观检测
      • raft算法——选举领头sentinel
    • 故障修复
      • 选出新master
      • 更改其他slaves的复制目标
      • 将旧master修改为slave

1. 概述

  • 概述:
    • 由一个或多个哨兵实例组成的哨兵系统可以监视任意多个主服务器及它们的从服务器
    • 如果某主服务器宕机,哨兵系统会自动选取该主服务器的某个从服务器作为新的主服务器,保证高可用性
  • 例子:
    • (1)正常运行(server1为主服务器,server2 / 3 / 4 为从服务器)
    • (2)此时server1意外宕机,哨兵系统察觉到其下线
    • (3)如果在规定时间内server1没上线,哨兵系统会重新选举
      • 选举:按照规则选出该宕机主服务器下的某个从服务器(图中为server2),升级它为新的主服务器
      • 故障转移:发送新的复制指令给其他从服务器(图中为server3和server4),让它们发送新的复制指令给主服务器(server2),进行复制
    • (4)当原先宕机的主服务器(server1)上线后,它将变成从服务器

2. 启动和初始化

  • 配置
    • Sentinel本身也是一个Redis服务器,只不过以哨兵模式运行。因此需要对conf进行配置
    • 假设有3个哨兵需要启动,主服务器的ip为192.168.11.128:6379,密码为123456
      • # 配置监听的主服务器,这里sentinel monitor代表监控,mymaster代表服务器的名称,可以自定义,192.168.11.128代表监控的主服务器,6379代表端口,2代表只有两个或两个以上的哨兵认为主服务器不可用的时候,才会进行failover操作。
        sentinel monitor mymaster 192.168.11.128 6379 2
        # sentinel author-pass定义服务的密码,mymaster是服务名称,123456是Redis服务器密码
        # sentinel auth-pass <master-name> <password>
        sentinel auth-pass mymaster 123456
  • 启动命令

    • //命令1
      ./redis-sentinel ../sentinel.conf
      //命令2
      redis-server ../sentinel.conf --sentinel
  • 启动流程/步骤

    • 1. 初始化服务器

      • 相比普通Redis服务器,Sentinel不会载入RDB或者AOF文件

      • 执行 文件事件函数 和 时间事件函数,但是与普通Redis服务器不同

    • 2. 将普通Redis服务器使用的代码替换成Sentinel专用代码

      • Sentinel有专用的端口:26379,并不是6379

      • 函数命令表与普通Redis服务器也不同

    • 3. 初始化Sentinel状态

      • 初始化Sentinel特有的结构体:sentinelState,而不是redisServer

        • struct sentinelState{
              //当前纪元,用于实现故障转移
              uint64_t curent_epoch;
          
              //保存了所有这个sentinel监视的主服务器
              //key是主服务器名称,value是一个指向sentinelRedisInstance结构的指针
              dict *masters;
          
              //是否进入了TILT模式
              int tilt;
          
              //目前正在执行的脚本数量
              int running_scripts;
          
              //进入TILT模式的时间
              mstime_t tilt_start_time;
          
              //最后一次执行时间处理器的时间
              mstime_t previous_time;
          
              //一个FIFO队列,包含了所有需要执行的用户脚本
              list *scripts_queue;
          } sentinel;
    • 4. 根据conf文件,初始化Sentinel的监视主服务器列表

      • 记录在 *masters 字典中,key = 名称, value = sentinelRedisInstance 结构体

      • sentinelRedisInstance 可以是主服务器,从服务器 或者 另一个Sentinel

        • typedef struct sentinelRedisInstance {
              //标识值,记录了实例的类型,以及该实例的当前状态
              //主服务器:SRI_MASTER;从服务器:SRI_SLAVE
              int flags;
           
              //实例的名字
              //主服务器的名字由用户在配置文件中设置
              //从服务器以及Sentinel 的名字由Sentinel 自动设置
              //格式为ip:port ,例如"127.0.0.1:26379"
              char *name;
           
              //实例的运行ID
              char *runid;
           
              //配置纪元,用于实现故障转移
              uint64_t config_epoch;
           
              //实例的地址,也是哥结构体,保存ip和port
              sentinelAddr *addr;
          
              //如果是主服务器,需要记录其下的从服务器信息
              sentinelAddr *slaves
           
              // SENTINEL down-after-milliseconds 选项设定的值
              //实例无响应多少毫秒之后才会被判断为主观下线(subjectively down )
              mstime_t down_after_period;
           
              // SENTINEL monitor <master-name> <IP> <port> <quorum> 选项中的quorum 参数
              //判断这个实例为客观下线(objectively down )所需的支持投票数量
              int quorum;
           
              // SENTINEL parallel-syncs <master-name> <number> 选项的值
              //在执行故障转移操作时,可以同时对新的主服务器进行同步的从服务器数量
              int parallel_syncs;
           
              // SENTINEL failover-timeout <master-name> <ms> 选项的值
              //刷新故障迁移状态的最大时限
              mstime_t failover_timeout;
              // ...
          } sentinelRedisInstance;
      • eg. 
    • 5. 创建和主服务器的网络连接

      • Sentinel会成为主服务器的client,并向其发送命令,来获取相关的信息

      • Sentinel会创建两个连向主服务器的异步网络连接

        • 命令连接,用于发送和接受命令

        • 订阅连接,专门用于订阅主服务器的 __sentinel__: hello频道

3. Sentinel与主从服务器的交互

  • Sentinel初始化主服务器信息:每隔10s,向监视的主服务器们发送INFO命令,然后记录从服务器的ip和port
    • INFO命令,有两个用途
      • 更新主服务器的run_id和role
        • 主服务器每次重启,run_id会变
        • 主服务器如果宕机,重启后可能变成从服务器,sentinelRedisInstance的flags由SRI_MASTER变成SRI_SLAVE
      • 来获取对应从服务器的ip和port,记录在slaves结构中
  • Sentinel初始化从服务器信息:分为两步,建立连接 + 更新信息
    • 建立连接:根据从主服务器的slaves指针,向它们创建 命令连接 和 订阅连接
    • 更新信息:每10s一次发送info指令,提取以下信息更新在 sentinelRedisInstance 结构中
      • 从服务器的run_id
      • 从服务器的role
      • 该从服务器对应主服务器的 master_host + master_port,即ip+port
      • 主从服务器的连接状态 master_link_status
      • 从服务器的优先级 slave_priority
      • 从服务器的偏移量 slave_repl_offset
  • Sentinel向订阅频道发送信息:默认每2s,sentinel会向所有监视的主服务器和从服务器频道发送命令
    • 命令包含:(该sentinel自己的信息 + 主服务器的信息)
    • 注:
      • 如果是从服务器,收到的是(监视自己的sentinel的信息 + 自己follow的主服务器的信息)
      • 如果是主服务器,收到的是(监视自己的sentinel的信息 + 自己的信息)
  • Sentinel初始化其他Sentinel信息
    • 订阅连接:当Sentinel与一个主服务器或从服务器建立订阅连接后,他就会向服务器发送订阅命令,直到连接断开
      • SUBSCRIBE __sentinel__:hello
      • 根据前一条所知,Sentinel会向订阅频道发送信息,因此其他Sentinel也会收到
      • 如果收到的消息是自己发送的,丢弃;如果是其他Sentinel发送的,更新监视这个主服务器的其他Sentinel资料。即sentinelRedisInstance中的sentinels字典指针
    • 与其他Sentinel建立命令连接
      • 发现新的Sentinel后,会相互建立命令连接
      • 相互之间不会创建订阅连接
  • 总结
    • 1. 根据配置文件,初始化监视的 主服务器,记录在 sentinelState->masters(sentinelRedisInstance) 中
    • 2. 向主服务器发送 INFO,获取 对应从服务器 的ip和port,并发送INFO,记录在 sentinelState->masters(sentinelRedisInstance) -> slaves(sentinelRedisInstance) 中
    • 3. 与所有主从服务器建立命令连接和订阅频道
    • 4. sentinel定期向订阅频道发送信息
    • 5. 所有订阅频道的Sentinel会相互收到对方的信息,更新自己的sentinelState->masters(sentinelRedisInstance) -> sentinels(sentinelRedisInstance) ,并相互建立命令连接
  • 结构图

4. 下线判断和故障修复

下线判断分为三步:主观检测,客观检测,领头选举

  • 主观检测
    • 每个Sentinel会以1s一次的频率给所有实例(主 + 从 + 其他哨兵)发PING命令,会得到两种回复
      • 有效回复: 返回 +PONG, -LOADING, -MASTERDOWN 三种的任意一种
      • 无效回复:其他回复 或者 限定时间内没回复
    • 如果一个实例在 down-after-milliseconds 毫秒(根据conf配置)内都是无效回复,则标记为主观下线
    • sentinel会修改sentinelRedisInstance中的flags标志位,加入 SRI_S_DOWN标记
  • 客观检测
    • 当sentinel发现某master主观下线,便发送命令询问其他sentinel,并得到回复
      • #发送询问命令
        SENTINEL is-master-down-by-addr <ip> <port> <current_epoch> *
        #eg.  SENTINEL is-master-down-by-addr 127.0.0.1 6379 0 *
        #current_epoch表示当前纪元,用于之后的选举领头sentinel
        #当用于客观检测时:发送*;
        #当用于选举时:发送自己的run_id
        
        #得到回复命令
        1) 1    //1表示下线,0表示未下线
        2) *    //当用于客观检测回复时:发送*;当用于选举时,发送对方的sentinel run_id
        3) 0    //忽略,仅在 (2)!=* 时有效
    • 根据收到的回复和配置文件判断是否客观下线,如果客观下线,加入SRI_O_DOWN标记
      • #/conf文件
        #该配置表示 包括当前sentinel在内,只要总共有2个sentinel认为主服务器下线,则认定客观下线
        sentinel monitor master 127.0.0.1 6379 2
  • 选举领头Sentinel:raft算法
    • Raft一致性算法保障在任何时候一旦处于leader服务器当掉,可以在剩余正常工作的服务器中选举出新的Leader服务器更新新Leader服务器,修改从服务器的复制目标
    • 规则
      • 每个sentinel每轮选举,无论是否成功,epoch++,保证每轮大家epoch都一样,并且统计选举次数
      • 发现master客观下线的sentinel会立即发送命令给其他sentinel,要求大家选举自己为领头
      • 每个sentinel每轮只有一次投票机会,投给最先发给自己的sentinel,晚到的都丢弃不回复
      • 某个sentinel收到超过半数以上的票(假如10个sentinel,则需要6票),则获胜
      • 如果规定时间内没有选举成功,过一段时间继续选举,直到产生结果
    • eg.有三台sentinel:A,B,C
      • A最先发现master客观下线,B其次再发现
      • A发送    <SENTINEL is-master-down-by-addr master_ip master_port A_epoch A_run_id >     给B,C;B也是
      • C投给先到的A,丢弃B的;A投给自己;B投给自己
      • A的得票为2,选举成功

故障修复:指在领头sentinel的带领下选拔新的master

  • 从slaves中选出新master,向其发送 SLAVEOF no one 命令(根据优先级规则)
    • 断线/下线的slaves不考虑
    • 优先 最近心跳回复 正常的slave
    • 优先 offset大的,再 id 小的
  • 修改其他slaves的复制目标
    • 向它们发送 SLAVEOF 新master 命令
  • 将旧master修改为slave
    • 等它重新上线时,发送 SLAVEOF 新master 命令

Ref:

为什么slot共16384个:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值