Windows 故障转移群集 Part 1

Windows 故障转移群集 Part 1,第1张

对于现如今的IT运维来说,数据中心的应用和服务的高可用是重中之重,计划内或意外的宕机导致的业务停顿会直接造成经济损失,降低客户满意度进而破坏业内口碑,其重要性不言而喻。

高可用的系统要求部署可靠容错机制和运维手段,以便在出现单点故障时能及时检测并尽量降低业务中断时长,故障群集即为此目的应运而生。

在部署Windows Server 2012 R2故障转移群集之前,我们需要充分考虑集群所需的必要组件以便我们能够顺利的配置它。

集群仲裁( Quorum )用于定义当集群中至少有多少节点参与集群才能保证故障转移保护正常工作,每个节点都进行投票,票数满足仲裁设定则仲裁才可以开始或继续运行。当集群的节点数为偶数时,可以将集群配置为允许磁盘或者共享文件夹来作为见证( Witness )参与投票。为保证集群功能与性能正常,每个节点复制有包含投票数量的集群配置信息并会同步更新。

Windows Server 2012中,安装故障转移集群时,安装向导会自动选择默认仲裁模式,一旦集群安装完成,仲裁模式将被配置为如下两者之一,仲裁模式可在集群an'zhuang'wan'cheng'hou

从Windows Server 2012 R2 起,windows故障转移集群引入动态仲裁。在集群安装完成时,将默认使用动态仲裁模式。所谓动态仲裁模式,集群服务会根据集群中的节点数量动态修改集群仲裁模式,若节点数变为偶数,将启用磁盘见证( Witness ),使用节点磁盘多数仲裁;若节点数位奇数,将自动禁止磁盘见证( Witness )投票,使用节点多数仲裁,简而言之,动态仲裁会在节点故障时重新计算仲裁进而改变仲裁配置并保证集群正常提供服务。动态仲裁模式下,当新增或驱逐节点时,不需要手动配置仲裁模式。

Windows Server 2012 R2 还引入了强制仲裁弹性功能( force quorum resilience ),此功能被用在集群被拆分,集群节点互相无法感知的情况下,即脑裂( Split Brain )场景。用以强制使服务可用。

本例使用Window Server 2012 R2 搭建iSCSI存储

准备Target

在集群定时任务 clusterCron 中,会遍历集群中的节点,对每个节点进行检查,判断节点是否下线。与节点下线相关的状态有两个,分别为 CLUSTER_NODE_PFAIL 和 CLUSTER_NODE_FAIL 。

CLUSTER_NODE_PFAIL :当前节点认为某个节点下线时,会将节点状态改为 CLUSTER_NODE_PFAIL ,由于可能存在误判,所以需要根据集群中的其他节点共同决定是否真的将节点标记为下线状态, CLUSTER_NODE_PFAIL 可以理解为疑似下线,类似哨兵集群中的主观下线

CLUSTER_NODE_FAIL :集群中有过半的节点标认为节点已下线,此时将节点置为 CLUSTER_NODE_FAIL 标记节点下线, CLUSTER_NODE_FAIL 表示节点真正处于下线状态,类似哨兵集群的客观下线

在集群定时任务遍历集群中的节点进行检查时,遍历到的每个节点记为 node ,当前节点记为 myself ,检查的内容主要有以下几个方面:

一、判断孤立主节点的个数

如果当前节点 myself 是从节点,正在遍历的节点 node 是主节点,并且 node 节点不处于下线状态,会判断孤立节点的个数,满足以下三个条件时,认定 node 是孤立节点,孤立节点个数增1:

二、检查连接

这一步主要检查和节点间的连接是否正常,有可能节点处于正常状态,但是连接有问题,此时需要释放连接,在下次执行定时任务时会进行重连,释放连接需要同时满足以下几个条件:

三、疑似下线判断

ping_delay 记录了当前时间距离向 node 节点发送PING消息的时间, data_delayd 记录了 node 节点向当前节点最近一次发送消息的时间,从ping_delay和data_delay中取较大的那个作为延迟时间。

如果延迟时间大于超时时间,判断 node 是否已经处于 CLUSTER_NODE_PFAIL 或者 CLUSTER_NODE_FAIL 状态,如果都不处于,将节点状态置为 CLUSTER_NODE_PFAIL ,认为节点疑似下线。

上述检查完成之后, 会判断当前节点是否是从节点,如果不处于 CLUSTER_MODULE_FLAG_NO_FAILOVER 状态,调用 clusterHandleSlaveFailover 处理故障转移,不过需要注意此时只是将节点置为疑似下线,并不满足故障转移条件,需要等待节点被置为FAIL下线状态之后,再次执行集群定时任务进入到 clusterHandleSlaveFailover 函数中才可以开始处理故障转移。

当前节点认为某个node下线时,会将node状态置为 CLUSTER_NODE_PFAIL 疑似下线状态,在定时向集群中的节点交换信息也就是发送PING消息时,消息体中记录了node的下线状态,其他节点在处理收到的PING消息时, 会将认为node节点下线的那个节点加入到node的下线链表fail_reports中,并调用 markNodeAsFailingIfNeeded 函数判断是否有必要将节点置为下线FAIL状态

markNodeAsFailingIfNeeded

markNodeAsFailingIfNeeded用于判断是否有必要将某个节点标记为FAIL状态:

clusterHandleSlaveFailover

由上面的内容可知,节点客观下线时会被置为 CLUSTER_NODE_FAIL 状态,下次执行集群定时任务时,在故障转移处理函数 clusterHandleSlaveFailover 中,就可以根据状态来检查是否需要执行故障转移。

不过在看 clusterHandleSlaveFailover 函数之前,先看一下 clusterState 中和选举以及故障切换相关的变量定义:

clusterHandleSlaveFailover函数中的一些变量

data_age : 记录从节点最近一次与主节点进行数据同步的时间 。如果与主节点处于连接状态,用当前时间减去最近一次与master节点交互的时间,否则使用当前时间减去与master主从复制中断的时间。

auth_age : 当前时间减去发起选举的时间 ,也就是距离发起选举过去了多久,用于判断选举超时、是否重新发起选举使用。

needed_quorum : quorum的数量,为集群中节点的数量的一半再加1

auth_timeout : 等待投票超时时间。

auth_retry_time : 等待重新发起选举进行投票的时间,也就是重试时间

一、故障转移条件检查

首先进行了一些条件检查,用于判断是否有必要执行故障转移,如果 处于以下几个条件之一,将会跳出函数,结束故障转移处理

二、主从复制进度校验

cluster_slave_validity_factor 设置了故障切换最大主从复制延迟时间因子,如果不为0需要校验主从复制延迟时间是否符合要求。

如果主从复制延迟时间 data_age 大于 mater向从节点发送PING消息的周期 + 超时时间 * 故障切换主从复制延迟时间因子 并且不是手动执行故障切换,表示主从复制延迟过大,不能进行故障切换终止执行。

三、是否需要重新发起选举

如果距离上次发起选举的时间大于超时重试时间,表示可以重新发起投票。

四、延迟发起选举

五、发起投票

如果满足执行故障的条件,接下来需从节点想集群中的其他节点广播消息,发起投票,不过只有主节点才有投票权。 failover_auth_sent 为0表示还未发起投票,此时开始发起投票:

六、执行故障切换

当某个节点获取到了集群中大多数节点的投票,即可进行故障切换,这里先不关注,在后面的章节会讲。

clusterGetSlaveRank用于计算当前节点的等级,遍历所属主节点的所有从节点,根据主从复制进度 repl_offset 计算, repl_offset 值越大表示复制主节点的数据越多,所以等级越高,对应的 rank 值就越低。

从节点在发起选举使用了 rank 的值作为延迟时间,值越低延迟时间越小,意味着选举优先级也就越高。

当从节点认为主节点故障需要发起投票,重新选举主节点时,在集群中广播了 CLUSTERMSG_TYPE_FAILOVER_AUTH_REQUEST 消息,对应的处理在 clusterProcessPacket 函数中,里面会调用 clusterSendFailoverAuthIfNeeded 函数进行投票:

clusterSendFailoverAuthIfNeeded

clusterSendFailoverAuthIfNeeded函数用于进行投票,处理逻辑如下:

以上条件校验通过, 表示当前节点可以投票给发送请求的节点,此时更新 lastVoteEpoch ,记录最近一次投票的纪元(轮次),更新投票时间 node->slaveof->voted_time ,然后向发起请求的节点回复 CLUSTERMSG_TYPE_FAILOVER_AUTH_ACK 消息。

主节点对发起投票请求节点的回复消息 CLUSTERMSG_TYPE_FAILOVER_AUTH_ACK 同样在消息处理函数 clusterProcessPacket 中,会对发送回复消息的节点进行验证:

同时满足以上三个条件时, 表示发送者对当前节点进行了投票,更新当前节点记录的收到投票的个数, failover_auth_count 加1,此时有可能获取了大多数节点的投票,先调用 clusterDoBeforeSleep 设置一个 CLUSTER_TODO_HANDLE_FAILOVER 标记,在周期执行的时间事件中会调用对状态进行判断决定是否执行故障转移。

从节点收到投票后,会添加 CLUSTER_TODO_HANDLE_FAILOVER 标记,接下来看下对 CLUSTER_TODO_HANDLE_FAILOVER 状态的处理。

在 beforeSleep 函数(server.c文件中),如果开启了集群,会调用 clusterBeforeSleep 函数,里面就包含了对 CLUSTER_TODO_HANDLE_FAILOVER 状态的处理:

beforeSleep 函数是在Redis事件循环 aeMain 方法中被调用的,详细内容可参考 事件驱动框架源码分析 文章。

clusterBeforeSleep

在clusterBeforeSleep函数中,如果节点带有 CLUSTER_TODO_HANDLE_FAILOVER 标记,会调用 clusterHandleSlaveFailover 函数进行处理:

clusterHandleSlaveFailover 函数在上面我们已经见到过,这次我们来关注集群的故障转移处理。

如果当前节点获取了大多数的投票,也就是 failover_auth_count (得到的投票数量)大于等于 needed_quorum , needed_quorum 数量为集群中节点个数的一半+1,即可执行故障转移,接下来会调用 clusterFailoverReplaceYourMaster 函数完成故障转移。

clusterFailoverReplaceYourMaster

如果从节点收到了集群中过半的投票,就可以成为新的master节点,并接手下线的master节点的slot,具体的处理在clusterFailoverReplaceYourMaster函数中,主要处理逻辑如下:

总结


欢迎分享,转载请注明来源:夏雨云

原文地址:https://www.xiayuyun.com/zonghe/807840.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-08-29
下一篇2023-08-29

发表评论

登录后才能评论

评论列表(0条)

    保存