JavaJVM · Java虚拟机原理 · JVM上语言·框架· 生态系统

Redis中Sentinel高可用解决方案

2020-07-08  本文已影响0人  熊聘

Sentinel(哨兵、哨岗)是Redis的高可用(high availability)解决方案:由一个或多个Sentinel实例组成Sentinel系统可以监视任意多个主服务器以及它们属下的所有从服务器,并在监视主服务器进行下线时,将主服务器下属的从服务器升级为新的主服务器,然后由新的主服务器代替已下线的主服务器继续处理命令请求。

Redis的Sentinel主从服务关系图

Redis的Sentinel主从服务关系图

从Redis的Sentinel主从服务关系中可以看出:

启动并初始化Sentinel

Sentinel本质上只是一个运行在特殊模式下的Redis服务器,所以启动Sentinel的第一步就是初始化一个普通的Redis服务器,并将普通Redis服务器使用的代码替换成Sentinel专用代码,然后再进行初始化,具体如下:

  1. 初始化Sentinel状态
struct sentinelState {
    // sentinel id
    char myid[CONFIG_RUN_ID_SIZE+1];
    // 当前纪元,用于实现故障转移
    uint64_t current_epoch;
    // 保存了所有被这个sentinel监视的主服务器
    // 字典的键是主服务的名字
    // 字典的只则是一个指向sentinelRedisInstance结构的指针
    dict *masters; 
    // 是否进入了TILT模式
    int tilt;
    // 目前正在执行的脚本的数量
    int running_scripts;
    // 进入TILT模式的时间
    mstime_t tilt_start_time;
    // 最后一次执行时间处理器的时间
    mstime_t previous_time;
    // 一个FIFO队列,包含了所有需要执行的用户脚本
    list *scripts_queue;
} sentinel;

主要初始化Sentinel相关的基础信息,其中masters属性表示该Sentinel需要监听的所有master实例,这些数据都是通过sentinel.conf配置文件获取的

  1. 初始化Sentinel状态的masters属性
typedef struct sentinelRedisInstance {
    // 标识值,记录了实例的类型以及该实例的当前状态
    int flags;
    // 实例的名字
    // 主服务器的名字由用户在配置文件中的设置
    // 从服务器以及Sentinel的名字由Sentinel自动设置
    // 格式为ip:port,例如"127.0.0.1:26397"
    char *name;
    // 实例运行的ID
    char *runid;
    // 配置纪元,用于实现故障转移
    uint64_t config_epoch;
    // 实例的地址
    sentinelAddr *addr;
    // 实例无响应多少毫米之后才会被判断为主观下线
    mstime_t down_after_period; 
    // 监听同一个master节点的其它sentinel
    dict *sentinels;
    // master的所有slave节点
    dict *slaves;
    // 判断这个实例客观下线所需的支持投票数量
    unsigned int quorum;
    // ......
    // master实例
    struct sentinelRedisInstance *master;
    // 如果是master实例,表示执行故障转移的sentinel的runid
    // 如果是sentinel,表示被投票成leader的sentinel的runid
    char *leader;
    // 刷新故障迁移状态的最大时限
    mstime_t failover_timeout;
    // ......
} sentinelRedisInstance;

sentinelState.masters中的实例为sentinelRedisInstance的master对象。sentinelRedisInstance.slaves表示该master对象对应的所有slave,sentinelRedisInstance.sentinels表示该master对象所有被监听的sentinel

  1. 创建连向主服务器的网络连接
    初始化Sentinel时需要创建连向被监视器主服务器的网络连接,Sentinel将成为主服务器的客户端,它可以向主服务器发送命令,并从命令回复中获取相关的信息。每个Sentinel会创建两个连向主服务器的异步网络连接:

获取主服务器信息

Sentinel默认会以每十秒一次的频率,通过命令连接向被监视的主服务器发送INFO命令,并通过分析INFO命令的回复来获取主服务器的当前信息。Sentinel可以获取以下两个方面的信息:

获取从服务器信息

当Sentinel发现主服务器有新的从服务器出现时,Sentinel除了会为这个新的从服务器创建相应的实例结构之外,Sentinel还会创建连接到从服务器的命令连接和订阅连接。

接收来自主服务器和从服务器的频道信息

Sentinel会对__sentinel__:hello频道的订阅一直持续到Sentinel与服务器的连接断开为止。当一个Sentinel收到从__sentinel__:hello频道的一条信息,会对信息进行分析并,然后如下操作:

检测主观下线状态

默认情况下,Sentinel以每秒一次的频率向所有其它创建了命令连接的实例(包括主服务器、从服务器、其它Sentinel在内)发送PING命令,并通过PING命令回复来判断实例是否在线

如果一个实例在down-after-milliseconds毫米内(Sentinel配置文件中配置项),连续向Sentinel返回无效回复,那么Sentinel会在这个实例中flags属性中打开SRI_S_DOWN标识,以此来表示这个实例已经进入主观下线状态

检测客观下线状态

当Sentinel将一个主服务器判定为主观下线之后,为了确保这个主服务器是否真的下线,它会询问其它同样监视这一主服务器的其它Sentinel,具体步骤如下:

Sentinel选举

当一个主服务器被判定为客观下线时,监视这个主服务器的所有Sentinel会进行协商,选出一个leader执行故障转移,选举规则如下:

故障转移

选举产生最为leader的Sentinel将执行对主服务器的故障转移操作,主要包含三个步骤:

  1. 在已下线的主服务器的所有从服务器中挑选一个从服务器将其转换为新的主服务器
  2. 让已下线的主服务器的所有从服务器改为复制新的主服务器
  3. 将已下线主服务器设置为新的主服务器的从服务器,当这个久的主服务器重新上线时,它就会成为新的主服务器的从服务器

相关知识点

上一篇 下一篇

猜你喜欢

热点阅读