Redis设计与实现 学习笔记 第十六章 Sentinel

news2024/11/27 21:45:57

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

图16-1展示了一个Sentinel系统监视服务器的例子:
在这里插入图片描述
上图中:
1.用双环图案表示主服务器server1。

2.用单环图案表示从服务器server2、server3、server4。

3.Sentinel系统监视所有四个服务器。

假设这时,主服务器server1进入下线状态,那么从服务器server2、server3、server4对主服务器的复制操作将被中止,且Sentinel系统会察觉到server1已下线,如图16-2所示:
在这里插入图片描述
当server1的下线时长超过用户设定的下线时长上限时,Sentinel系统就会对server1执行故障转移操作:
1.首先,Sentinel系统会挑选server1属下的一个从服务器,并将这个被选中的从服务器升级为新的主服务器。

2.之后,Sentinel系统会向server1属下的从服务器发送新的复制指令,让它们成为新的主服务器的从服务器,当所有从服务器都开始复制新的主服务器时,故障转移操作执行完毕。

3.另外,Sentinel还会继续监视已下线的server1,并在它重新上线时,将它设置为新的主服务器的从服务器。

例如,图16-3展示了Sentinel系统将server2升级为新主服务器,并让server3和server4成为server2的从服务器的过程:
在这里插入图片描述
之后,如果server1重新上线,它将被Sentinel系统降级为server2的从服务器,如图16-4所示:
在这里插入图片描述
16.1 启动并初始化Sentinel

启动一个Sentinel可以使用命令:
在这里插入图片描述
或命令:
在这里插入图片描述
这两个命令的效果完全相同。

当一个Sentinel启动时,它需要执行以下步骤:
1.初始化服务器。

2.将普通Redis服务器使用的代码替换成Sentinel专用代码。

3.初始化Sentinel状态。

4.根据给定的配置文件,初始化Sentinel的监视主服务器列表。

5.创建连向主服务器的网络连接。

16.1.1 初始化服务器

因为Sentinel本质上只是一个运行在特殊模式下的Redis服务器,所以启动Sentinel的第一步,就是初始化一个普通的Redis服务器,其初始化过程类似于第14章中的普通Redis的初始化过程,但因为Sentinel执行的工作与普通Redis服务器不同,所以Sentinel的初始化过程与普通Redis服务器的初始化过程不完全相同。

例如,Sentinel不会载入RDB文件或AOF文件。
在这里插入图片描述
16.1.2 使用Sentinel专用代码

启动Sentinel的第二个步骤就是将一部分普通Redis服务器使用的代码替换成Sentinel专用代码。比如说,普通Redis服务器使用redis.h/REDIS_SERVERPORT常量值作为服务器端口:
在这里插入图片描述
而Sentinel使用sentinel.c/REDIS_SENTINEL_PORT常量作为服务器端口:
在这里插入图片描述
此外,普通Redis服务器使用redis.c/redisCommandTable作为服务器的命令表:
在这里插入图片描述
而Sentinel使用sentinel.c/sentinelcmds作为服务器的命令表,且其中的INFO命令会使用Sentinel模式下的专用实现sentinel.c/sentinelInfoCommand函数,而非普通Redis服务器使用的实现redis.c/infoCommand函数:
在这里插入图片描述
sentinelcmds命令表也解释了为什么在Sentinel模式下,Redis服务器不能执行诸如SET、DBSIZE(获取当前数据库键数量)、EVAL等命令,因为服务器根本没在命令表中载入这些命令。PING、SENTINEL、INFO、SUBSCRIBE、UNSUBSCRIBE、PSUBSCRIBE、PUNSUBSCRIBE这七个命令就是客户端能对Sentinel执行的全部命令了。

16.1.3 初始化Sentinel状态

在应用了Sentinel的专用代码后,接下来,服务器会初始化一个sentinel.c/sentinelState结构(简称Sentinel状态),这个结构保存了服务器中所有和Sentinel功能有关的状态(服务器的一般状态仍由redis.h/redisServer结构保存):

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;

16.1.4 初始化Sentinel状态的masters属性

Sentinel状态中的masters字典记录了所有被Sentinel监视的主服务器的相关信息,其中:
1.字典的键是被监视主服务器的名字。

2.字典的值是被监视主服务器对应的sentinel.c/sentinelRedisInstance结构。

每个sentinelRedisInstance结构(后面简称“实例结构”)代表一个被Sentinel监视的Redis服务器实例,这个实例可以是主服务器、从服务器、另一个Sentinel,但masters属性中只保存主服务器的实例结构。

实例结构包含的属性非常多,以下代码展示了实例结构在表示主服务器时使用的一部分属性:

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,即Sentinel主观地认为实例下线了)
    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>选项的值
    // 故障迁移时间超出此值时,Sentinel将放弃这次尝试
    mstime_t failover_timeout;
    // ...
} sentinelRedisInstance;

sentinelRedisInstance.addr属性是一个指向sentinel.c/sentinelAddr结构的指针:

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

对Sentinel状态的初始化将引发对masters字典的初始化,而masters字典的初始化是根据被载入的Sentinel配置文件来进行的。

例如,用户在启动Sentinel时,指定了包含以下内容的配置文件:
在这里插入图片描述
那么Sentinel将为主服务器master1创建如图16-5所示的实例结构:
在这里插入图片描述
并且Sentinel会为主服务器master2创建如图16-6所示的实例结构:
在这里插入图片描述
而这两个实例会被保存到Sentinel状态的masters字典中,如图16-7所示:
在这里插入图片描述
16.1.5 创建连向主服务器的网络连接

初始化Sentinel的最后一步是创建连向被监视主服务器的网络连接,Sentinel将成为主服务器的客户端,它可以向主服务器发送命令,并获取命令回复。

对于每个对Sentinel监视的主服务器来说,Sentinel会创建两个连向主服务器的异步网络连接:
1.一个是命令连接,专门用于向主服务器发送命令,并接收命令回复。

2.另一个是订阅连接,专门用于订阅主服务器的__sentinel__:hello频道。

图16-8展示了一个Sentinel向被它监视的两个主服务器master1和master2创建命令连接和订阅连接的例子:
在这里插入图片描述
16.2 获取主服务器信息

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

例如,假设主服务器master有三个从服务器slave0、slave1、slave2,且一个Sentinel与主服务器建立了连接,那么Sentinel将持续向主服务器发送INFO命令,并得到类似以下内容的回复:
在这里插入图片描述
通过分析主服务器返回的INFO命令回复,Sentinel可获取以下两方面信息:
1.一方面是关于主服务器本身的信息,包括run_id域记录的服务器运行ID、role域记录的服务器角色。

2.另一方面是关于主服务器属下的从服务器的信息,每个从服务器都由一个“slave”字符串开头的行记录,每行的ip域记录了从服务器的IP、port域记录了从服务器的端口。根据IP和端口,Sentinel无须用户提供从服务器的地址信息,就可以自动发现从服务器。

根据run_id和role域记录的信息,Sentinel将对主服务器的实例结构进行更新,例如,主服务器重启后,它的运行ID就会变化,Sentinel检测到这一情况后,就会对实例结构的运行ID进行更新。

主服务器返回的从服务器信息会用于更新主服务器实例结构的slaves字典,这个字典记录了主服务器属下从服务器的名单:
1.字典的键是Sentinel自动设置的从服务器名,格式为ip:port。

2.字典的值是从服务器对应的实例结构。

Sentinel在分析INFO命令中包含的从服务器信息时,会检查从服务器对应的实例结构是否已经存在于slaves字典:
1.如果从服务器对应的实例结构已存在,那么Sentinel将对其进行更新。

2.如果从服务器对应的实例结构不存在,那么Sentinel将为这个从服务器创建一个实例结构。

对于上图的例子,Sentinel将分别为三个从服务器创建它们各自的结构,并将这些结构保存到主服务器实例结构的slaves字典里,如图16-10所示:
在这里插入图片描述
注意上图中主从服务器实例结构之间的区别:
1.主服务器实例结构的flags属性值为SRI_MASTER,而从服务器的是SRI_SLAVE。

2.主服务器实例结构的name属性是用户使用Sentinel配置文件设置的,而从服务器的是ip:port。

16.3 获取从服务器信息

当Sentinel发现主服务器有新从服务器出现时,Sentinel除了会为这个从服务器创建相应的实例结构,还会创建到从服务器的命令连接和订阅连接,如图16-10所示:
在这里插入图片描述
在创建命令连接后,Sentinel默认每十秒一次通过命令连接向从服务器发送INFO命令,并获得类似以下内容的回复:
在这里插入图片描述
根据INFO命令的回复,Sentinel会提取出以下信息:
1.从服务器的运行ID run_id。

2.从服务器的角色role。

3.主服务器的IP地址master_host和端口号master_port。

4.主从服务器的连接状态master_link_status。

5.从服务器的优先级slave_priority。

6.从服务器的复制偏移量slave_repl_offset。

根据这些信息,Sentinel会对从服务器的实例结构进行更新,图16-12展示了Sentinel根据上面的INFO命令回复对从服务器的实例更新之后的结果:
在这里插入图片描述
16.4 向主服务器和从服务器发送信息

默认Sentinel会以两秒一次的频率,通过命令连接向所有被监视的主服务器和从服务器发送以下格式的命令:
在这里插入图片描述
这条命令向服务器的__sentinel__:hello频道发送了一条信息,信息的内容由以下参数组成:
1.以s_开头的参数记录的是Sentinel本身的信息,参数的意义见表16-2:
在这里插入图片描述
2.以m_开头的参数记录的是主服务器的信息,各个参数的意义见表16-3:
在这里插入图片描述
16.5 接收来自主服务器和从服务器的频道信息

当Sentinel与一个主服务器或从服务器建立起订阅连接后,Sentinel会通过订阅连接,向服务器发送以下命令:
在这里插入图片描述
Sentinel对__sentinel__:hello频道的订阅会一直持续到Sentinel与服务器的连接断开为止。

即,对每个与Sentinel连接的服务器,Sentinel既通过命令连接向服务器的__sentinel__:hello频道发送信息,又通过订阅连接接收服务器的__sentinel__:hello频道的信息,如图16-13所示:
在这里插入图片描述
对于监视同一个服务器的多个Sentinel来说,一个Sentinel发送的信息会被其他Sentinel接收到,这些信息被用于更新其他Sentinel对发送信息的Sentinel的认知,也被用于更新其他Sentinel对被监视服务器的认知。

例如,现在有sentinel1、sentinel2、sentinel3三个Sentinel在监视同一服务器,当sentinel1向服务器的__sentinel__:hello频道发送一条信息时,所有订阅了__sentinel__:hello频道的Sentinel(包括sentinel1自己在内)都会收到这条信息,如图16-14所示:
在这里插入图片描述
当一个Sentinel从__sentinel__:hello频道收到一条信息时,Sentinel会对这条信息进行分析,提取出信息中的Sentinel IP地址、Sentinel端口、Sentinel运行ID等八个参数,并进行以下检查:
1.如果信息中的Sentinel运行ID和自身的相同,说明这条信息是自己发出的,Sentinel将丢弃这条信息,不做处理。

2.如果信息中的Sentinel运行ID和自身的不同,说明这条信息是监视同一个服务器的其他Sentinel发来的,接收信息的Sentinel将根据信息中的参数,对相应主服务器的实例结构进行更新。

16.5.1 更新sentinels字典

Sentinel为主服务器创建的实例结构sentinelRedisInstance中有一个sentinels字典,其中除了Sentinel本身的实例结构外,还有所有监视这个主服务器的Sentinel的实例结构:
1.sentinels字典的键是Sentinel的名字,格式为ip:port。

2.sentinels字典的值是所对应的Sentinel的实例结构。

当一个目标Sentinel收到来自其他源Sentinel发来的信息时,目标Sentinel会从信息中获取以下两方面参数:
1.与Sentinel有关的参数:源Sentinel的IP、端口、运行ID、配置纪元。

2.与主服务器有关的参数:源Sentinel正在监视的主服务器的名字、IP、端口号、配置纪元。

根据信息中提取出的主服务器参数,目标Sentinel会在自己的Sentinel状态的masters字典中查找相应的主服务器实例结构,然后根据提取出的Sentinel参数,检查主服务器实例结构的sentinuels字典中,源Sentinel的实例结构是否存在:
1.如果源Sentinel实例结构已存在,则更新它。

2.如果源Sentinel实例结构不存在,那么说明这个Sentinel是刚开始监视主服务器的新Sentinel,此时会为这个新Sentinel创建实例结构并将其添加到sentinels字典里。

例如,有127.0.0.1:26379、127.0.0.1:26380、127.0.0.1:26381三个Sentinel正在监视主服务器127.0.0.1:6379,那么当127.0.0.1:26379收到以下信息时:
在这里插入图片描述
Sentinel将执行以下操作:
1.第一条信息的发送者为127.0.0.1:26379,是自己发送的,这条信息会被忽略。

2.第二条信息的发送者为127.0.0.1:26381,Sentinel会根据这条信息对sentinels字典中该发送者对应的实例结构进行更新。

3.第三条信息的发送者为127.0.0.1:26380,Sentinel会根据这条信息对sentinels字典中该发送者对应的实例结构进行更新。

图16-15展示了Sentinel 127.0.0.1:26379为主服务器127.0.0.1:6379创建的实例结构,以及其中的sentinels字典:
在这里插入图片描述
其他两个Sentinel也会创建类似上图的sentinels字典,区别在于其中只保存了除自己外的其他正在监视该主服务器的Sentinel。

因为一个Sentinel可通过分析接收到的频道信息来获知其他Sentinel的存在,并通过发送频道信息来让其他Sentinel知道自己的存在,所以用户使用Sentinel时不需要提供各个Sentinel的地址信息,监视同一个主服务器的多个Sentinel可以自动发现对方。

16.5.2 创建连向其他Sentinel的命令连接

当Sentinel通过频道信息发现一个新Sentinel时,它不仅会为新Sentinel在sentinels字典中创建相应的实例结构,还会创建一个连向新Sentinel的命令连接,而新Sentinel也同样会创建连向这个Sentinel的命令连接:
在这里插入图片描述
使用命令连接相连的各个Sentinel可向其他Sentinel发送命令请求来进行信息交换。

Sentinel之间不会创建订阅连接,Sentinel在连接主服务器或从服务器时创建订阅连接是为了通过频道发来的信息来发现新Sentinel,所以才需要建立订阅连接,而Sentinel之间没有建立订阅连接的需要。

16.6 检测主观下线状态

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

在图16-17展示的例子中,带箭头的连线表示发送PING命令:
在这里插入图片描述
实例对PING命令的回复可分为:
1.有效回复:+PONG、-LOADING、-MASTERDOWN三种。

2.无效回复:除有效回复外的其他回复,或指定时限内没有返回的回复。

Sentinel配置文件中的down-after-milliseconds选项指定了Sentinel判断实例进入主观下线所需的毫秒数:如果一个实例在指定毫秒内,连续向Sentinel返回无效回复,那么Sentinel会修改这个实例对应的实例结构,在结构的flags属性中打开SRI_S_DOWN标识,以此来表示实例进入了主观下线状态,例如:
在这里插入图片描述
down-after-milliseconds会被Sentinel用来判断主服务器、从服务器、其他Sentinel的主观下线状态。

对于监视同一个主服务器的多个Sentinel来说,这些Sentinel设置的down-after-milliseconds选项值可能不同,因此,当一个Sentinel将主服务器判断为主观下线时,其他Sentinel可能仍认为主服务器处于在线状态。

16.7 检查客观下线状态

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

16.7.1 发送SENTINEL is-master-down-by-addr命令

Sentinel使用:
在这里插入图片描述
命令询问其他Sentinel是否同意主服务器已下线,命令参数的意义见表16-4:
在这里插入图片描述
例如,被Sentinel判断为主观下线的主服务器IP为127.0.0.1,端口号为6379,且Sentinel当前配置纪元为0,那么Sentinel将向其他Sentinel发送以下命令来询问主服务器的下线状态:
在这里插入图片描述
16.7.2 接收SENTINEL is-master-down-by-addr命令

当一个目标Sentinel接收到另一个源Sentinel发来的SENTINEL is-master-down-by命令时,目标Sentinel会检查要查询的主服务器是否已下线,然后向源Sentinel返回一条包含以下三个参数的Multi Bulk(可用于包含多个值的请求或回复,如MSET命令获取多个键的值时使用)作为回复:
1.<down_state>

2.<leader_runid>

3.<leader_epoch>

表16-5记录了这三个参数的意义:
在这里插入图片描述
16.7.3 接收SENTINEL is-master-down-by-addr命令的回复

根据其他Sentinel发回的SENTINEL is-master-down-byaddr命令回复,Sentinel将统计同意主服务器已下线的Sentinel数量,当达到配置指定的判断客观下线所需的数量时,Sentinel会将主服务器实例结构flags属性的SRI_O_DOWN表示打开,表示主服务器已进入客观下线状态:
在这里插入图片描述
例如,Sentinel在启动时载入了以下配置:
在这里插入图片描述
那么包括当前master在内,只要总共有两个Sentinel认为主服务器已进入下线状态,那么当前Sentinel就将主服务器判断为客观下线。

对于监视同一个主服务器的多个Sentinel来说,它们将主服务器判断为客观下线的条件可能不同。

16.8 选举领头Sentinel

当一个主服务器被判断为客观下线时,监视这个下线主服务器的各个Sentinel会进行协商,选举出一个领头Sentinel,并由领头Sentinel对下线主服务器执行故障转移操作。

以下是Redis选举领头Sentinel的规则和方法:
1.所有在线的Sentinel都有被选为领头Sentinel的资格,即,监视同一个主服务器的所有在线Sentinel都有可能成为领头Sentinel。

2.每次进行领头Sentinel选举后,不论选举是否成功,所有Sentinel的配置纪元(configuration epoch)都会自增。配置纪元实际就是一个计数器。

3.在一个配置纪元里,所有Sentinel都有一次将某个Sentinel设为局部领头Sentinel的机会,且一旦局部领头Sentinel被设置,在这个配置纪元里就不能再更改。

4.每个发现主服务器进入客观下线的Sentinel都会要求其他Sentinel将自己设为局部领头Sentinel。

5.当一个源Sentinel向另一个目标Sentinel发送SENTINEL is-master-down-by-addr命令,且命令中的runid参数不是*号而是源Sentinel的运行ID时,这表示源Sentinel要求目标Sentinel将前者设为后者的局部领头Sentinel。

6.Sentinel设置局部领头Sentinel的规则是先到先得:最先向目标Sentinel发送设置要求的原Sentinel将成为目标Sentinel的领头Sentinel,之后接收到的所有设置要求都会被目标Sentinel拒绝。

7.目标Sentinel接收到SENTINEL is-master-down-by-addr命令后,将向源Sentinel返回一条命令回复,回复中的leader_runid和leader_epoch参数分别记录了目标Sentinel的局部领头Sentinel的运行ID和配置纪元。

8.源Sentinel接收到目标Sentinel返回的命令回复后,会检查回复中leader_epoch参数的值和自己的配置纪元是否相同,如果相同,那么源Sentinel继续取出回复中的leader_runid参数,如果leader_runid参数的值和源Sentinel的运行ID一致,那么表示目标Sentinel将源Sentinel设置成了局部领头Sentinel。

9.如果有某个Sentinel被半数以上Sentinel设置成了局部领头Sentinel,那么这个Sentinel成为领头Sentinel。例如,在一个由10个Sentinel组成的Sentinel系统里,只要有大于等于6个Sentinel将某个Sentinel设置为局部领头Sentinel,那么被设置的那个Sentinel就会成为领头Sentinel。

10.因为领头Sentinel的产生需要半数以上Sentinel的支持,并且每个Sentinel在每个配置纪元里只能设置一次局部Sentinel,所以在一个配置纪元里,只会出现一个领头Sentinel。

11.如果给定时限内没有一个Sentinel被选举为领头Sentinel,那么各个Sentinel将在一段时间后再次进行选举,直到选出领头Sentinel为止。

为了熟悉以上规则,我们来看一个选举领头Sentinel的过程。

假设有三个Sentinel正在监视同一主服务器,且这三个Sentinel之前已经通过SENTINEL is-master-down-by-addr命令确认主服务器进入了客观下线状态,如图16-20所示:
在这里插入图片描述
那么为了选出领头Sentinel,三个Sentinel将再次向其他Sentinel发送SENTINEL is-master-down-by-addr命令,如图16-21所示:
在这里插入图片描述
和检测客观下线状态时发送的SENTINEL is-master-down-by-addr命令不同,Sentinel这次发送的命令会带有Sentinel自己的运行ID,例如:
在这里插入图片描述
如果接受到上图所示命令的Sentinel还没有设置局部领头Sentinel,它就会将发送该命令的Sentinel设置为自己的局部领头Sentinel,并返回类似以下的命令回复:
在这里插入图片描述
然后接收到命令回复的Sentinel就可根据这一回复,统计出有多少Sentinel将自己设置成了局部领头Sentinel。

根据命令请求发送的先后顺序不同,可能会有某个Sentinel的SENTINEL is-master-down-by-addr命令比其他Sentinel发送的相同命令更快到达,并最终胜出领头Sentinel的选举,然后这个领头Sentinel就可以开始对主服务器执行故障转移操作了。

有个疑问,如果有4个Sentinel,1和2是互相的局部领头Sentinel,3和4是互相的局部领头Sentinel,且由于网络原因(1、2在一起,3、4在一起,且1、2和3、4离得很远),每次执行选举都是这个结果,岂不是永远不会出现领头Sentinel了?因为没有一个Sentinel是3个Sentinel的局部领头Sentinel。

16.9 故障转移

在选举产生出领头Sentinel后,领头Sentinel将对已下线的主服务器执行故障转移操作,该操作包含三个步骤:
1.在已下线主服务器属下的所有从服务器里,挑一个将其转换为主服务器。

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

3.让已下线的主服务器设为新主服务器的从服务器,当这个旧的主服务器重新上线时,它会成为新的主服务器的从服务器。

16.9.1 选出新的主服务器

第一步会挑选一个状态良好、数据完整的从服务器,然后向其发送SLAVEOF no one命令,将其转换为主服务器。

新的主服务器是怎样选出来的?领头Sentinel会将已下线主服务器的所有从服务器保存到一个列表里,然后按以下规则对列表进行过滤:
1.删除列表中所有处于下线或断线状态的从服务器。

2.删除列表中所有近5秒没有回复过领头Sentinel的INFO命令的从服务器。

3.删除所有与已下线主服务器连接断开超过10*down-after-milliseconds毫秒数的从服务器,这可以保证从服务器的数据是比较新的。

之后,领头Sentinel根据从服务器的优先级,对列表中剩余的从服务器进行排序,并选出优先级最高的从服务器。

如果有多个并列最高优先级的从服务器,那么领头Sentinel会选择复制偏移量最大的从服务器。

如果有多个并列最高优先级、并列最大复制偏移量的从服务器,那么领头Sentinel会选择运行ID最小的从服务器。

图16-22展示了在一次故障转移操作中,领头Sentinel向被选中的从服务器发送SLAVEOF no one命令的情形:
在这里插入图片描述
在发送SLAVEOF no one命令后,领头Sentinel会以每秒一次的频率(平时是十秒一次),向被升级的从服务器发送INFO命令,并观察命令回复中的角色(role)信息,当其从slave变为master时,领头Sentinel就知道升级成功了。

例如,在图16-22展示的例子中,领头Sentinel会一直向server2发送INFO命令,当server2返回的命令从:
在这里插入图片描述
变为:
在这里插入图片描述
领头Sentinel就知道server2已经成功升级为主服务器了。

图16-23展示了server2升级成功后,各个服务器和领头Sentinel的样子:
在这里插入图片描述
16.9.2 修改从服务器的复制目标

当出现新主服务器后,领头Sentinel下一步要做的就是,让已下线主服务器属下的所有从服务器去复制新的主服务器,这一动作可通过向从服务器发送SLAVEOF命令来实现。
在这里插入图片描述
在这里插入图片描述
16.9.3 将旧的主服务器变为从服务器

因为旧的主服务器server1已下线,所以将server1设为从服务器的设置只是修改Sentinel中server1对应的实例结构,当server1重新上线时,Sentinel就会向它发送SLAVEOF命令,让它成为server2的从服务器。

16.10 重点回顾

1.Sentinel只是一个运行在特殊模式下的Redis服务器,它使用了和普通模式不同的命令表,所以Sentinel模式能够使用的命令和普通Redis服务器能够使用的命令不同。

2.Sentinel会读入用户指定的配置文件,为每个要被监视的主服务器创建相应的实例结构,并创建连向主服务器的命令连接和订阅连接,其中命令连接用于向主服务器发送命令请求,而订阅连接用于接收指定频道的消息。

3.Sentinel通过向主服务器发送INFO命令来获得主服务器属下所有从服务器的地址信息,并为这些从服务器创建相应的实例结构,以及连向这些从服务器的命令连接和订阅连接。

4.一般情况下,Sentinel每十秒一次向被监视的主服务器和从服务器发送INFO命令,当主服务器处于下线状态,或Sentinel正在对主服务器进行故障转移操作时,Sentinel向从服务器发送INFO命令的频率会改为每秒一次。

5.对于监视同一个主服务器和从服务器的多个Sentinel来说,它们会以每两秒一次的频率,通过向被监视服务器的__sentinel__:hello频道发送消息来向其他Sentinel宣告自己的存在。

6.每个Sentinel也会从__sentinel__:hello频道中接收其他Sentinel发来的信息,并根据这些信息为其他Sentinel创建相应的实例结构,以及命令连接。

7.Sentinel只会与主服务器和从服务器创建命令连接和订阅连接,Sentinel与Sentinel之间只创建命令连接。

8.Sentinel以每秒一次的频率向实例(主服务器、从服务器、其他Sentinel)发送PING命令,并根据实例对PING命令的回复来判断实例是否在线,当一个实例在指定时长中连续向Sentinel发送无效回复时,Sentinel会将这个实例判断为主观下线。

9.当Sentinel将一个主服务器判断为主观下线时,它会向同样监视这个主服务器的其他Sentinel进行询问,看它们是否同意这个主服务器已进入下线状态。

10.当Sentinel收集到足够多的主观下线投票后,它会将主服务器判断为客观下线,并发起一次针对主服务器的故障转移操作。

16.11 参考资料

Sentinel系统选举领头Sentinel的方法是对Raft算法的领头选举方法的实现,关于这一方法的详细信息可参考Raft算法的论文。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2235775.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

前端三件套-css

一、元素选择器 元素选择器&#xff1a;利用标签名称。p,h1-h6...... 行内样式&#xff08;内联样式&#xff09;&#xff1a;例如<p style"color:red;font-size:50px"> id选择器&#xff1a;针对某一个特定的标签来使用。以#定义。 class&#xff08;类&a…

MoonBit 双周报 Vol.59:新增编译器常量支持,改进未使用警告,支持跨包函数导入...多个关键技术持续优化中!

2024-11-04 MoonBit更新 增加了编译期常量的支持。常量的名字以大写字母开头&#xff0c;用语法 const C ... 声明。常量的类型必须是内建的数字类型或 String。常量可以当作普通的值使用&#xff0c;也可以用于模式匹配。常量的值目前只能是字面量&#xff1a; const MIN_…

新疆高校大数据实验室案例分享

高校大数据实验室建设&#xff0c;企业可以提供技术支持、实训平台和项目案例&#xff0c;高校则提供科研和教学资源&#xff0c;实现产学研一体化。不仅有利于大数据技术的应用和人才培养也有利于区域发展。 泰迪与新疆合作的院校包括新疆大学、昌吉学院等 新疆大…

Capcut,更适合做TikTok运营的“剪映”

剪映这一次的更新&#xff0c;可谓是引来许多视频创作者的怒火。原本免费的功能&#xff0c;更新之后需要vip才能使用了&#xff1b;原本的vip功能&#xff0c;则需要升级至svip&#xff0c;甚至一些功能&#xff0c;需要会员积分才能使用。 许多运营TikTok的小伙伴一直在用剪映…

linux centos 安装redis

安装 wget https://download.redis.io/releases/redis-7.4.0.tar.gz解压redis-7.4.0.tar.gz文件 tar -zxvf redis-7.4.0.tar.gz进入redis安装目录 cd redis-7.4.0make时报错&#xff0c;因为需要安装gcc&#xff0c;gcc安装需要联网安装 修改端口 编辑文件用vi。nano命令cen…

第一个纯血鸿蒙应用(Napi开发-ArtTS调用C/C++)

1.行业背景 纯血鸿蒙&#xff0c;即鸿蒙Next版已于2014年1月正式发版&#xff0c;鸿蒙生态设备数量已经突破10亿台&#xff0c;已经有超过15000个应用和元服务上架。鸿蒙生态不只是移动设备这么简单&#xff0c;他打造的是一个18n的全场景战略&#xff0c;真正做到了“万物互联…

2.ARM_ARM是什么

CPU工作原理 CPU与内存中的内容&#xff1a; 内存中存放了指令&#xff0c;每一个指令存放的地址不一样&#xff0c;所需的内存空间也不一样。 运算器能够进行算数运算和逻辑运算&#xff0c;这些运算在CPU中都是以运算电路的形式存在&#xff0c;一个运算功能对应一种运算电…

【Ant.designpro】上传图片

文章目录 一、前端二、后端 一、前端 fieldProps:可以监听并且获取到组件输入的内容 action{“/api/upload_image”} 直接调用后端接口 <ProFormUploadButtonlabel{"上传手续图片"}name{"imgs"}action{"/api/upload_image"}max{5} fieldPro…

CSS基础知识六(浮动的高度塌陷问题及解决方案)

目录 1.浮动高度塌陷概念 2.下面是几种解决高度塌陷的几种方案&#xff1a; 解决方案一&#xff1a; 解决方案二&#xff1a; 解决方案三&#xff1a; 1.浮动高度塌陷概念 在CSS中&#xff0c;高度塌陷问题指的是父元素没有正确地根据其内部的浮动元素或绝对定位元素来计…

【云原生开发】K8S集群管理后端开发设计与实现

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

计算机网络——SDN

分布式控制路由 集中式控制路由

qt QTableWidgetItem详解

1、概述 QTableWidgetItem 是 Qt 框架中的一个类&#xff0c;专门用于在 QTableWidget&#xff08;一个基于项的表格视图&#xff09;中表示单个单元格的内容。QTableWidget 继承自 QAbstractItemView&#xff0c;而 QTableWidgetItem 则作为表格中的一个单元格项&#xff0c;…

DevExpress中文教程 - 如何使用AI模型检查HTML编辑中的语法?

DevExpress .NET MAUI多平台应用UI组件库提供了用于Android和iOS移动开发的高性能UI组件&#xff0c;该组件库包括数据网格、图表、调度程序、数据编辑器、CollectionView和选项卡组件等。 目前许多开发人员正在寻找多种方法将AI添加到解决方案中&#xff08;这通常比想象的要…

vue中html如何转成pdf下载,pdf转base64,忽略某个元素渲染在pdf中,方法封装

一、下载 html2Canvas jspdf npm install jspdf html2canvas二、封装转换下载方法 htmlToPdf.js import html2Canvas from html2canvas import JsPDF from jspdf/*** param {*} reportName 下载时候的标题* param {*} isDownload 是否下载默认为下载&#xff0c;传false不…

day05(单片机)SPI+数码管

目录 SPI数码管 SPI通信 SPI总线介绍 字节交换原理 时序单元 ​​​​​​​SPI模式 模式0 模式1 模式2 模式3 数码管 介绍 74HC595芯片分析 ​​​​​​​原理图分析 ​​​​​​​cubeMX配置​​​​​​​ 程序编写 硬件SPI ​​​​​​​软件SPI 作业&#xff1a; SPI数…

越学越爽!4小时从零入门大模型教程,2024最详细的学习路线,让你少走99%弯路!(大模型/LLM/Agent/提示工程)

第一阶段&#xff1a;基础理论入门 目标&#xff1a;了解大模型的基本概念和背景。 内容&#xff1a; 人工智能演进与大模型兴起。 大模型定义及通用人工智能定义。 GPT模型的发展历程。 第二阶段&#xff1a;核心技术解析 目标&#xff1a;深入学习大模型的关键技术和工…

论文速读:简化目标检测的无源域适应-有效的自我训练策略和性能洞察(ECCV2024)

中文标题&#xff1a;简化目标检测的无源域适应&#xff1a;有效的自我训练策略和性能洞察 原文标题&#xff1a;Simplifying Source-Free Domain Adaptation for Object Detection: Effective Self-Training Strategies and Performance Insights 此篇文章为论文速读&#xff…

小白入门学习计算机辅助工具--Git和Github

虽然平时大家都有听过Github&#xff0c;但这实际上要分为Git和Github&#xff0c;我们可以简单理解为前者是用于本地&#xff0c;后者是远程端。下面我们来看看一些基本的操作。 Github创建仓库 让我们先从Github开始&#xff0c;点击右边的绿色按钮new进入创建库界面&#x…

【C++】哈希表封装 unordered_map 和 unordered_set 的实现过程

C语法相关知识点可以通过点击以下链接进行学习一起加油&#xff01;命名空间缺省参数与函数重载C相关特性类和对象-上篇类和对象-中篇类和对象-下篇日期类C/C内存管理模板初阶String使用String模拟实现Vector使用及其模拟实现List使用及其模拟实现容器适配器Stack与QueuePriori…

攀拓(PAT)- 程序设计(乙级)2024年春季考试

题目来源&#xff1a;https://pintia.cn/market/item/1767454903977603072 B-1 题目要求 2024 这个数字&#xff0c;可以由 n n n个互不相同的正偶数和 m m m个互不相同的正奇数组合出来吗&#xff1f;本题就请你回答这个问题。 输入格式&#xff1a; 输入在一行中给出一个…