高可用(一):Redis Sentinel 系统

一、介绍

Redis 通过 Sentinel系统保证自身的高可用性。Sentinel系统是由一个或者多个Sentinel实例组成,如图1和图2所示:它会实现的监视Redis 服务器主机机器及其从机的运行状态,当某个服务器主机被Sentinel系统认为客观下线的时候,Sentienel 系统的是从其可用的从机中选取一个升级为新的主机,下线主机则会成为新主机的从机,重新上线会从新的主机中同步数据。

图1:服务器和sentinel系统

图2:主机服务器下线

二、Sentienl 实例

Sentienl实质也是一个redis的服务器的,但是但不承担数据的读写任务只负责监视起的其他redis服务器。作为sentienl 运行的服务器和普通服务器在启动时加载的指令集也是不一样的,只加载用通信和监视的几个指令(ping, sentinel, subscribe, unsubscribe, psubscribe, punsubscribe, info,其中info 是专有的)。

三、Sentinel 相关源码解析

相关数据结构示意图.png
  1. struct sentinelState
    sentinelState 包含sentinel 运行时的所有状态和监视服务主机状态信息。
struct sentinelState {
    //sentinel 实例ID
    char myid[CONFIG_RUN_ID_SIZE+1]; 
    uint64_t current_epoch;       
    // 所监视redis 服务主机实例及信息
    dict *masters;      
    int tilt;           
    int running_scripts;    
    mstime_t tilt_start_time;      
    mstime_t previous_time;        
    list *scripts_queue;            
    char *announce_ip;  
    int announce_port;  
    unsigned long simfailure_flags; 
    int deny_scripts_reconfig; 
} sentinel;
  1. struct sentinelRedisInstance
    sentinelRedisInstance 表示一个被监视的Redis服务器的状态和相关信息。
typedef struct sentinelRedisInstance {
    //标识主机状态
    int flags;      
    //服务器名
    char *name;
    // 服务器运行实例    
    char *runid;    
    uint64_t config_epoch;
    //服务器地址  
    sentinelAddr *addr; 
    ...
     //其他的sentinel服务器信息
    dict *sentinels;   
     // 服务器从机
    dict *slaves;       
     // 主机客观下线标准
    unsigned int quorum;
    ...
    // 主机主观下线标准
    mstime_t master_link_down_time; 
    ...
   
    
} sentinelRedisInstance;

四、Sentinel如何监视主机服务器

  1. Sentinel 会和每个被监视的Redis服务器创建两个异步网络链接。
    • 命令链接:向服务器发送命令,并接受回复
    • 订阅链接:订阅服务器的 __sentinel__:hello 频道
  2. Sentinel 默认以每10秒一次的频率向被监视服务器,发送INFO指令,服务器收INFO指令后,会返回自身信息和从机信息等。Sentinel 接受之后会解析主机的信息和从机的信息(运行id, ip, port等等),然后更新sentienlRedisInstance中保存的主机信息(name, runid等等)和从机信息(slaves). 保存从机的信息的是一个键为地址(ip:port),值为sentinelRedisInstance字典类型,主机和从机都是通过sentinelRedisInstance保存信息, 通过设置flags 参数(SRI_MASTER,SRI_SLAVE) 可以区分主机和从机。
  3. 获取到从机地址后,Sentinel 也会和从机创建命令链接订阅链接,通过INFO,实时的获取从机信息,并更新保存

五、Sentinel 间如何相互协调

  1. Sentienl 在主从服务器建立好链接,会通过命令链接,订阅服务器的__sentinel__:hello频道
  2. Sentinel 会通过命令链接 以默认2秒一次的频率去向所有被监视的主服务器的__sentinel__:hello频道发送订阅信息。这个订阅信息包含sentinel 自身信息和接收命令的服务器信息(ip, port, id等)。所有订阅__sentinel__:hello的sentinel均可以收到信息。
  3. 通过订阅频道Sentinel之间可以获取对方的信息和其监视主机的信息,然后更新自身保存的服务器主机的信息,也将其他sentinel的信息进行保存。
  4. 通过从订阅频道获取到其他sentinel信息,sentinel之前也会建立命令链接进行通信和协调。

六、故障转移

  1. 主观下线:Sentinel 会以固定频率和和其建立命令链接的redis实例(主机,从机,sentinel)发送PING指令,根据回复判断其是否下线。若其在一定时间内无法进行有效回复,sentinel则认为该实例进入主观下线状态。其实主观下线可以理解某个sentinel基于自己的认知(网络时延,超时设置)对于某个实例是否下线的判断,所以不同的sentinel对于同一的redis实例的主观下线的判断可能时不一致的。
  2. 客观下线:当一个sentinel 认为某个实例主观下线了,他就和其他的sentinel进行沟通(命令链接),看看其他的sentinel 对于这个实例的判断,若一个sentinel 系统超过半数认为这个实例已经下线,则认为这个实例客观下线状态。
  3. 选取领头的Sentinel
    通过Raft 算法sentinel 之间投票选举出来Leader(详情见后文
  4. 故障转移
    • Leader 从下线主机服务器的从机服务器中选出最合适的从机服务器,将其升级为新的主机服务器
    • 让其他从机服务器复制新的主机服务器
    • 让下线的主机服务器成为新的主机服务器的从机,当其重新上线的时候,复制主机服务器。

七、Sentinel Leader选举

1. 规则
  • 每个sentinel 节点都可以成为Leader
  • sentinel 记录着选举回合数,每次选取无论是否成功回合数+1.
  • 每个回合每个sentinel只有一次投票的机会。
2. 方法
  • 每个发现服务器客观下线的sentinel,开始选举的时候,如果没有投票,就会投票给自己,并通过is-master-down-by-addr命令要求其他的sentinel 给自己投票, 其余sentinel收到指令会把自己投票结果返回给该sentinel.
  • 投票是遵守选到先得的原则,sentinel 在没投票的情况下先收到的谁的指令就投给谁票。
  • 每个sentinel 统计获得票数,如果超过半数就自动成为leader, 进行故障转移操作,并不需要通知其他的sentinel, 但他们观察的新的主机产生,自动结束选举。
  • 或没有sentinel 获得过半票数,进行新一轮选举。每个sentinel 开新选举的时间不一(会有固定延时+一个1s以内的随机时间)。

你可能感兴趣的:(高可用(一):Redis Sentinel 系统)