Redis学习之Sentinel(四)

目录

  1. Sentinel简介
  2. Sentinel服务器的初始化
  3. 获取主从服务器信息
  4. 向主从服务器发送接收消息
  5. 检测主观客观下线状态
  6. 选举领头Sentinel
  7. 故障转移

1. Sentinel简介

Sentinel是Redis高可用性的解决方案。一个或者多个Sentinel实力可以组成一个Sentinel系统,用来监视这些主从服务器,当主服务器下线时,还可以故障转移,重新选举。

这里写图片描述

2. Sentinel服务器的初始化

初始化分成5个步骤

  1. 初始化服务器
  2. 将普通的Redis服务器使用的代码替代成Sentinel专用代码
  3. 初始化Sentinel状态
  4. 初始化Sentinel的监视主服务器列表
  5. 创建连向主服务器的网络连接

步骤一:初始化服务器

Sentinel的初始化其实跟普通的redis服务器相似,包括三个步骤:
- 初始化服务器状态结构
- 载入配置选项
- 初始化服务器数据结构

步骤二:使用Sentinel专用代码

  • 普通Redis服务器使用redis.h/REDIS_SERVERPORT常量作为服务器的端口,而Sentinel使用sentinel.c/REDIS_SENTINEL_PORT常量的值作为服务器端口。

    
    #define REDIS_SERVERPORT 6379
    
    
    #define REDIS_SENTINEL_PORT 26379
    
  • 普通Redis服务器使用redis.c/redisCommandTable作为服务器的命令表:
    这里写图片描述

      而Sentinel使用sentinel.c/sentinelcmds作为服务器的命令表

这里写图片描述

      从上面的命令可以看出来,在Sentinel模式下,Reids服务器不能执行SET,DBSIZE等操作,而类似PING,SENTINEL,INFO这些命令就是客户端可以对Sentinel执行的命令。

步骤三:初始化Sentinel状态

Sentinel的状态由 sentinelState结构来表示:

 struct sentinelState{

     //当前纪元,用于实现故障转移
     unit64_t current_epoch;

     //保存着被这个Sentinel监视的主服务器
     dict *masters;

     //是否进入TILT模式
     int tilt;

     //正在执行的脚本的数量
     int running_scripts;

     //进入TILT模式的时间
     mastime_t tilt_start_time;

     //最后一次执行时间处理器的时间
     mastime_t previous_time;

     //一个FIFO队列,包含了所有需要执行的用户脚本
     list *scripts_queue;
 }

步骤三:初始化Sentinel状态的masters属性

masters字典记录了所有被Sentinel监视的主服务器的相关信息:

  • 字典的键是被监视的主服务器的名字
  • 字典的值是被监视主服务器对应的sentinel.c/sentinelRedisInstance结构
typedef struct sentinelRedisinstance{
    //标记值,记录了实例的类型,以及该实例的当前状态。
    int flags;

    //实例名
    char *name;

    //实例运行ID
    char *runid;

    //配置纪元,用于故障转移
    unit64_t config_enpoch;

    //实例的地址
    sentinelAddr *addr;

    //从服务器
    sentinelRedisinstance *slaves;

    //实例 无响应多少毫秒被认为主观下线
    mstime_t down_after_period;

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

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

实例的addr属性是一个指向sentinelAddr结构的指针,保存着实例的ip地址和端口号。

typedef struct sentinelAddr{
    char *ip;
    int port;
}  

现在初始化的Sentinel状态的redis服务器结构为:

这里写图片描述

主从服务器的关系:

这里写图片描述

步骤五:创建连向主服务器的网络连接

初始化Sentinel的最后一步就是创建连向被监视主服务器的网络连接。Sentinel会创建两个连向主服务器的异步网络连接。

  • 一个是命令连接,专门向主服务器发送命令,并接受回复。
  • 一个是订阅连接,这个连接用于订阅主服务器的sentinel_:hello频道。

3. Sentinel获取主从服务器的信息

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

例如发送了INFO命令,从主服务器中获得回复如下:

#Server
···
run_id:32423ku4h23ohsdfsjklh3289fddsjk
···

# Repilication
role:master
···
slaver0:ip=127.0.0.1,prot=11111,state=online,offset=43,lag=0;
slaver1:ip=127.0.0.1,prot=22222,state=online,offset=43,lag=0;
slaver2ip=127.0.0.1,prot=33333,state=online,offset=43,lag=0;
···

# Other sections

因此可以获取到主服务器本身的信息,run_id记录了服务器运行ID,以及role域记录了服务器角色;而且可以获取slave的信息。因此可以根据这些域对Sentinel服务器的状态结构进行更新。

同理,如果发送INFO命令给从服务器,从服务器会回复如下:

#Server
···
run_id:382974oilfhdsakjfhwqowrws3245df
···

#Repilication
roleslave
master_host:127.0.0.1
master_port:6379
master_link_status:up
slave_repl_offset:11887
slave_priority:100

#Other sections

因此,同样可以获取从服务器的很多信息,然后Sentinel服务器对从服务器的实例结构进行更新。

4. 向主从服务器发送接收消息

发送

默认情况下,Sentinel会以每两秒一次的频率向它监视的主从服务器发送以下格式的命令:

PUBLSIT __sentinel__:hello "<s_ip><s_port><s_runid><s__epoch><m_name><m_ip><m_port><m_enpoch"

其中s代表Sentinel信息, m代表主服务器信息

接收

Sentinel会通过订阅连接,并向服务器发送以下命令:

SUBSCRIBE __sentinel__:hello

于是这个Sentinel就能订阅这个频道的消息。

处理消息

Sentinel为主服务器的实例结构sentinelRedisInstance有一个字段sentinels字典,储存着监视着这个主服务器的sentinels。

所以一个Sentinel收到一条消息,它先查看消息发送者,如果是自身,那么将忽略这条消息,如果不是自身,则根据消息对sentinelRedisInstance的sentinels字典进行更新。

建立连接

当Sentinel通过频道信息发现了一个新的Sentinel,它不仅会为新的Sentinel创建相应的数据结构,还会创建一个连向新的Sentinel的命令连接,新的Sentinel也会同样创建一个连向这个Sentinel的连接。所以,监听同一个服务器的几个Sentinel会形成网络。

这里写图片描述

5. 主观客观下线状态

主观下线 : Sentinel每秒一次向与它创建命令连接的实例发送ping命令,并通过是实例返回的ping回复来判断是否在线。回复有+PONG,-LOADING,-MASTERDOWN和无效回复,如果不是+PONG就可以认为这个这个实例主观下线。

客观下线 :当Sentinel将一个主服务器判断为主观下线之后,为了确认这个主服务器是否真的下线了,它会向同样监视这一个主服务器的其他Sentinel进行询问,看他们是否也认为主服务器已经进入了下线状态,如果数量超过sentinelRedisInstance结构中的quorum参数,那么认为客观下线,于是就进行主服务器的选举和故障转移。

6. 选举领头Sentinel

每个Sentinel都有成为领头的能力,而且每次选举无论是否成功,都会将配置纪元(confuguration epoch)的值自增,它实际上就是一个计数器。

局部领头:当一个Sentinel A向另一个Sentinel B发送请求SENTINEL is-master-down-by-addr + (Sentinel A 的 runid )代表A想成为B的局部领头。

所以这种规则就是先到先得,最早向目标Sentinel发送这个命令的必然成为它的Sentinel,后面的命令都会无效,当它的票数超过半数时,它就成为领头Sentinel,然后对已经下线的主服务器执行故障转移操作。

7. 故障转移

在选举出领头的Sentinel之后,领头Sentinel对已经下线的主服务器执行故障转移操作。步骤为:

  1. 在已下线的主服务器属下的所有从服务器里面,挑选一个从服务器,并将其转换为主服务器。(根据从服务器优先级,相同优先级选择复制偏移量较大的从服务器)

  2. 让已下线属下的所有从服务器改为复制新的主服务器,并成为新的主服务器的从服务器。

  3. 当旧的主服务器重新上线之后,它就会成为新的主服务器的从服务器。

猜你喜欢

转载自blog.csdn.net/qq_33394088/article/details/80587588