Redis---哨兵

    Redis高可用解决方案:有一个或者多个哨兵组成哨兵系统,监控服务系统,当主服务器下线,自动将其下的从服务器升级为主服务器(这里感觉哨兵就是一个管理者,但是权限不高)

 

一  启动并初始化Sentinel

  1.初始化服务器:Sentinel本质还是一个redis服务器,但是由于不适用数控功能,所以Sentinel的启动就不需要加载持久化数据了,简化得多,比如数据库创建,事务,脚本等等功能不再使用,哨兵更注重的是订阅功能,详细请看下表:

  2.使用Sentinel专用代码:将redis服务器启动的代码替换为Sentinel专用代码,切换使用的端口,切换命令表

  3.初始化Sentinel状态sentinelState结构(称为Sentinel状态),该结构保存了服务器中所有和Sentinel相关的状态,服务器的一般状态仍然使用redisServer结构保存,

struct sentineState{
    //当前纪元,用于实现故障转移
    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;

  4.初始化Sentinel中的masters属性:它是一个字典,记录了所有被监视的主服务器信息,键是服务器名字,值是sentinelRedisInstance实例

typedef struct sentinelRedisInstance{
    //标识值,记录了实例的类型,以及该实例的当前状态
    int flags;
    
    //实例的名字
    //主服务器的名字 由用户在配置文件中设置
    //从服务器以及 Sentinel  的名字由 Sentinel 自动设置
    //格式为ip:port  例如“127.0.0.1:26379”
    char *name;

    //实例的运行ID
    char *runid;
    //配置纪元,用于实现故障转移
    uint64_t config_epoch;
    // 实例的地址
    sentinelAddr *addr;

    // SENTINEL down-after-milliseconds 选项设定的值
    //实例无响应多少毫秒之后才会被判断为 主管下线
    metime_t down_after_period;

    //判断这个实例 为客观下线,所需的支持投票数量
    int quorum;

    //在执行故障转移操作时,可以同时对新的主服务器进行同步的从服务器数量
    int parallel)syncs;
    
    //刷新故障迁移状态的最大时限
    mstime_t failover_timeout;
    //...
}sentinelRedisInstance;

在masters字典初始化的过程中,会根据载入的Sentinel配置文件来进行,

所以sentinel管理的 主从服务器的添加,就是在配置文件中直接添加。

  5.创建练习主服务器的网络连接:Sentinel作为主服务器的客户端,它可以向主服务器发送命令,sentinel有两个连接,一个是命令连接,另外一个是订阅连接

二  获取服务器信息

1.获取master信息 

   Sentinel默认是十秒一次发送INFO命令,通过分析回复获得主服务器的当前信息,可以获得主的运行id,服务器角色,还有其下面的从服务器信息,ip,port等。例如下方:

    Sentinel对master的实例结构进行更新,根据返回的slave信息,更新,如果发现有salve是sentinel没有保存的,那么就是一个新的从服务器,需要建立连接(还是两个),实例同样使用sentinelRedisInstance,但是标志位属性进行了区分:master和slave。

master在sentinel的保存情况:

  master的RedisInstance对象中的name值是根据 sentinel-config配置文件中的值设置的,而它的slave对象的name值直接根据Ip:port自动生成的。

2.获取slave信息

  当sentinel发现新的slave的时候,会与slave建立连接,与sentinelRedisInstance实例,建立命令连接之后,Sentinel默认会以10s的频率发送INFO命令,获得下面的回复:

上面的信息包括:ip port role,run_id,master_linke_status,还有salve_priority。以及salve_repl_offset复制偏移量

三  sentinel与master和slave的交互

1.sentinel发送信息

  Sentinel会以2s/次的频率,通过命令向所有被监视的master和slave发送一下格式的命令:

 它向服务器的 __sentinel__:hello 频道发送了一条信息,s_开头的是sentinel本身的信息,m_开头的是master的信息。

2.sentinel接收信息

  当订阅连接建立之后,sentinel会向server发送:SUBSCRIBE __sentinel__:hello,对__sentinel__:hello频道的订阅会一直持续到sentinel与服务器的连接断开为止。

  所以sentinel通过命令连接向服务器的__sentinel__:hello频道发送信息,又通过订阅连接从服务器的__sentinel__:hello接收信息。

这也做的目的是:进行sentinel之间的通信,因为一个服务器可能不止一个监视器,当server通过订阅连接返回的时候,返回的是所以连接路线,所以监视它的sentinel都会收到信息,如此就进行了sentinel之间的通信。

  1.更新sentinels字典:它保存了其他sentinel监视这个master的信息。如ip,端口,运行id等。保存位置位于sentinelRedisInstance结构的sentinels属性中,它也是一个dict结构,而sentinel的保存,同样使用sentinelRedisInstance结构来保存,标识位为:SRI_SENTINEL。 所以,sentinel在发送信息的时候,会连带发送自己的信息,这样的目的就是暴露自己。

  2.创建连向其他Sentinel的命令连接:注意只有命令连接,因为订阅连接目的就是用来发现sentinel的。

 

四  下线状态

   1.主观:每秒一次向所有命令连接发送ping,sentinel根据配置文件中的down-after-milliseconds时间来判断server是否下线,如果下线就会修改SentinelRedisInstance的flags属性值,修改为:SRI_S_DOWN标识。

   主观下线时长的范围:down-after-milliseconds的值,不仅用来标识sentinel的监听是否下线,同时还标识主从之间是否下线,注意多个sentinel设置的下线时间可能不同,所以判断一个server是否真正下线,还需要进行投票选择。

  2.客观当本哨兵检测主服务器下线,会询问同时检测这个master的其他snetinel,是否判断下线,当sentinel从其他sentinel收到足够数量的down之后,sentinel就会客观的认为master下线,之后就会进行故障转移操作。

   询问其他Sentinel,某master是否下线的命令格式:is-master-down-by-addr ip port current_epoch  runid

  当sentinel收到上方的命令,会提取出ip和port,分析该master是否下线,然后回复三个参数:

down_state: 返回对master的检查结果,1表示下线,0表示正常

leader_runid: *符号 用来检查master状态,如果是局部领头sentinel的运行id,用来选举leader

leader_epoch:局部领头sentinel的配置纪元,用于选举leader。如果runid为*,则epoch为0

五  选举领头Sentinel

   主客观下线之后,监视它的哨兵会协商,选举出领头哨兵,让它对下线master执行故障转移。

1.所以监视master的sentinel都有资格

2.每次进行leader选举之后,无论选举是否成功,纪元epoch都会+1

3.在一个配置纪元里面,所有sentinel都有一次将某个sentinel设置为局部领头sentinel的机会。设置后不能更改。

4.每个发现master客观下线的sentinel都会要求其他sentinel将自己设置为局部leader

5.当源sentinel向目标sentinel发送上方is-master-down-by-addr命令的时候,runid参数不是*,而是源sentinel的id,则要求目标sentinel将自己的局部leader设置为源sentinel。

6.sentinel设置局部leader的原则是先到先得,之后再发送设置请求的将被拒绝。

7.目标sentinel收到上方命令后,将回复命令,也是上方三个参数:目标sentinel的局部leader id和配置epoch纪元。

8.源sentinel收到目标sentinel的回复之后,比较返回参数的epoch和自己的epoch是否相同,相同在比较runId是否相同,如果相同,则表明自己被设置为局部Leader,当自己的支持者超过半数,就会成为leader。

9.当规定时间内,没有产生Leader,则重新进行选举。

 

六  故障转移

  1.选出新的master:挑选出一个slave,向这个slave发送SLAVEOF no one命令,如何挑选这个slave呢?

leader sentinel会把下线的master的所有slave保存到一个列表里面,然后按照下面的规则进行过滤:

    1.删除列表中所有下线or短线的server

    2.删除列表中最近5s没有回复过leader的Info命令的slave

    3.删除列表中slave与下线master断开时间超过down-after-millisecods*10毫秒的salve,保证留下的slave的数据要最新。

  过滤之后,leader根据slave的优先级进行排序,选出优先级最高的slave。如果优先级并列的很多,再根据复制偏移量进行排序。如果还有多个,再进行runId进行排序,选择id最小的

  priority-->offset-->runId

  2.修改slave的复制目标:leader让下线master下的所有slave去复制新master,leader向slave发送SLAVEOF+master ip:port命令完成。

  3.将old master 变为slave:leader同样向slave发送SLAVEOF命令。

 

总结

图片源自:https://blog.csdn.net/JeremyJiaming/article/details/100117013

 

参考:《redis设计与实现》 读书笔记

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值