• redis高可用的哨兵模式实现


    Sentinel的作用

    SentinelRedis的高可用解决方案,由1-nSentinel实例组成的Sentinel系统,用来监视redis集群的主服务器,在主服务器下线时,自动将某个从服务器升级为新的主服务器,用来代替主服务器继续处理命令请求。

    例如,server1因为某种原因下线,Sentinel系统发现,就会将某个子服务器升级为新的主服务器,当server1再次上线时,就会变为server2的从服务器。

    (双环为主服务器,单环为从服务器)

    Sentinel的启动

    和redis服务的差别

    Sentinel本质是运行在特殊模式下的redis服务器,只是在初始化的部分和功能有所差别。
    在这里插入图片描述

    使用Sentinel的专用代码

    启动Sentinel会将一部分普通的reids服务器使用的代码替换成Sentinel的代码。

    初始化Sentinel状态

    Sentinel服务器初始化一个sentinel.c/sentinelState结构,保存了服务器中所有和Sentinel又能有关的状态。

    struct sentinelState {
    	// 当前纪元, 用于实现故障转移
    	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;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    初始化Sentinel状态的masters属性

    Sentinel状态中的masters字典记录了所有被Sentinel监视的主服务器的相关信息,其中:
    字典的键是被监视主服务器的名字;
    字典的值则是被监视主服务器对应的sentinel.c/sentinelRedisInstance结构。

    每个sentinelRedisInstance结构代表一个被Sentinel监视的的Redis服务器实例(可以是主/从服务器,也可以是另外的Sentinel)。
    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选项设定的值
    	//实例无响应多少毫秒之后才会被判断为主观下线(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;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    sentinelRedisInstance.addr指向sentinel.c/sentinelAddr结构的指针,保存着实例的IP和端口号:

    typedef struct sentinelAddr {
    	char *ip;
    	int port;
    } sentinelAddr;
    
    • 1
    • 2
    • 3
    • 4

    Sentinel的初始化,会引发对masters字典的初始化,masters字典的初始化是根据被载入的Sentinel配置文件来进行的。如果指定的配置文件为以下内容:

    #####################
    # master1 configure #
    #####################
    sentinel monitor master1 127.0.0.1 6379 2
    sentinel down-after-milliseconds master1 30000
    sentinel parallel-syncs master1 1
    sentinel failover-timeout master1 900000
    #####################
    # master2 configure #
    #####################
    sentinel monitor master2 127.0.0.1 12345 5
    sentinel down-after-milliseconds master2 50000
    sentinel parallel-syncs master2 5
    sentinel failover-timeout master2 450000
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    那么Sentinel将作为主服务器的master1master2创建如下结构:

    ### 创建连向主服务器的网络连接 初始化`Sentinel`的最后一步是创建连向被监视主服务器的网络连接,`Sentinel`将成为主服务器的客户端,他可以向主服务器发送命令,并从命令恢复中获取相关信息。

    Sentinel会创建两个连向被监视的主服务器的网络连接:

    • 命令连接,专门用于向主服务器发送命令,并接受命令恢复
    • 订阅连接,专门用于订阅主服务器的__sentinel__:hello频道
      在这里插入图片描述

    Sentinel和服务器之间的信息

    获取主服务器信息

    Sentinel默认10秒一次,通过命令连接向被监视的主服务器发送INFO命令,通过回复来获取主服务器的当前信息

    获取从服务器信息

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

    向主服务器和从服务器发送信息

    默认情况下,Sentinel会以2秒一次的频率,通过命令连接向所有被监视的主服务器和从服务器发送一下格式的命令:

    PUBLISH sentinel:hello “<s_ip>,<s_port>,<s_runid>,<s_epoch>,<m_name>,<m_ip>,<m_port>,<m_epoch>”

    这条命令向服务器的__sentinel__:hello频道发送了一条信息

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

    当Sentinel与一个主或从服务器简历起订阅连接之后,Sentinel就会通过订阅连接,向服务器发送以下命令:

    SUBSCRIBE sentinel:hello

    Sentinel对__sentinel__:hello频道的订阅会一直持续到Sentinel与服务器断开连接为止。

    也就是说,对于每个与Sentinel连接的服务器,Sentinel即通过命令连接向服务器的__sentinel__:hello频道发送信息,又能通过订阅连接从服务器的__sentinel__:hello频道接受信息。

    在这里插入图片描述

    检测主观下线状态

    默认情况下,Sentinel会以每秒一次的频率向所有与它创建命令连接的实例发送PING命令,并通过实例返回的PING命令回复来判断实例是否在线。

    检查客观下线状态

    当Sentinel将一个主服务器判断为主观下线之后,为了确认这个主服务器是否真的下线了,它会向其他同样监视这一主服务器的其他Sentinel进行询问,看他们是否也认为主服务器已经进入了下线状态。当Sentinel从其他Sentinel哪里接收到足够数量的已下线判断之后,Sentinel就会将从服务器判定为客观下线,并对主服务器进行故障转移操作。

    选举领头Sentinel

    故障转移

    在选举产生出领头Sentinel之后, 领头Sentinel将对已下线的主服务器执行故障转移操作, 该操作包含以下三个步骤:
    1) 在已下线主服务器属下的所有从服务器里面, 挑选出一个从服务器, 并将其转换为主服务器。
    2) 让已下线主服务器属下的所有从服务器改为复制新的主服务器。
    3) 将已下线主服务器设置为新的主服务器的从服务器, 当这个旧的主服务器重新上线时, 它就会成为新的主服务器的从服务器。

    内如主要来自《Redis设计与实现》,自己学习整理用

  • 相关阅读:
    天玑810和天玑900哪个好 天玑810和天玑900差距
    设计模式学习笔记 - 适配器模式
    第27期 | GPTSecurity周报
    【web前端开发】数据库MySQL在开发环境的操作
    Vue 项目中使用 Pinia 状态管理详细教程
    智慧公厕:打造更美好的城市生活环境
    ABAP-VL02N修改交货单外部标识BAPI
    个人教学网站设计
    hive 常用函数
    Apache Paimon 的 CDC Ingestion 概述
  • 原文地址:https://blog.csdn.net/qq1515312832/article/details/125616794