Ceph Monitor源码机制分析(三)—— 选举

Ceph Monitor源码机制分析(三)—— 选举

Monitor的选举机制
Monitor要做的事情很明确了,就是管理、维护和发布集群的状态信息,但是为了避免单点故障或者性能热点问题,一般使用多个Monitor来做这一件事情,也就是管理层有多个成员。集群的正常运行,首先需要管理层达成一致,达成一致就需要有一个能拍板的monitor(leader),大家都听它的就行了。所以要达成一致核心问题就是在众多monitor中选出那个能拍板的monitor。Ceph解决这个问题的方法很简单,有点类似于领导人的选举,即有资格的monitor先形成一个quorum(委员会),然后委员会的成员在quorum这个范围内选出一个leader,集群状态信息的更新以及quorum成员的维护就有这个leader负责。Leader的选取规则也比较简单,每个monitor在初始化的时候都会根据它的IP地址被赋予一个rank值,当选举leader时,rank值最小的monitor胜出当选leader。当quorum成员发生变化时(增加或者减少),都会触发重新选举流程,再选出一个leader。

整个Monitor的选举过程也是Monitor根据以下状态机进行状态变化的过程:

即Monitor在启动之后,会根据monmap发现其他的monitor并获取其他monitor的monmap、paxos版本等信息,然后酌情syncronize数据并触发quorum范围内的选举,选举之后monitor要么成为Leader要么成为Peon,直到服务停掉。

 

这么说还是有点笼统,让我们用代码说话吧,当然你得学会看代码。选举的入口函数是Monitor::start_election(),查一下调用这个函数的代码,不难看出会在以下三种情况发生时,调用它:

Monitor::handle_probe_reply(), monitor进行bootstrap时,首先会向monmap中所有的成员发送MMonProbe消息,然后在收到peer返回的probereply时,会根据返回的quorum信息以及paxos版本来判定是否需要发起选举。
Elector::handle_propose(),这个是在收到别的monitor发过来的选举请求消息时,会根据情况触发重新选举。
Monitor::do_admin_command()和Monitor::handle_command(),这两个属于通过ceph命令或者mon的admin socket执行quorumenter和quorum exit触发的选举操作。
这里详细介绍一下在第一种情况下触发的选举,并以此梳理一下整个选举过程。

  Monitor::bootstrap(),monitor进程的启动逻辑,具体做了以下几件事:

开始时设置monitor的状态为STATA_PROBING
然后判断是否设置了mon_compact_on_bootstrap参数,如果设置了,就执行compact操作,对monitor的store进行压缩
如果集群只有一个monitor,则该monitor直接胜出
根据mon_probe_timeout重置probe_timeout事件的时间
如果monitor在monmap中,则将其将如到outside_quorum集合中。
根据monmap,向其他peer一一发送MMonProbe消息。 
Monitor收到消息,经过dispatch逻辑之后进入Monitor::dispatch_op(),解析出来是MSG_MON_PROBE类型的消息,进而进入Monitor::handle_probe(),然后进入Monitor::handle_probe_reply进行处理。

  Monitor::handle_probe_reply(),在这里主要做了以下几件事。

先判断当前monitor所处的状态如果是Probing或者Electing,则直接退出。
比对对方的monmap和自己monmap的epoch版本,如果自己的monmap版本低,则更新自己的map,然后重新进入bootstrap()阶段。
如果当前Monitor处于synchronizing阶段,则直接返回
比对彼此的paxos的版本,如果对方的paxos版本较低,否则判断是否需要进行data的sync。这里有两种情况,如果自己的paxos版本是比对方的paxos_first_version纪录的版本低,则会进行sync操作。如果自己paxos的版本和对方的版本相差太远超过了设置的参数paxos_max_join_drift的值,也会先进行数据的sync而不会触发重新的选举操作。
如果从返回的消息中判断已经有一个quorum存在了,自己也在monmap中摒弃自己的ip地址不为空,则直接发起一个选举。否则,会请求加入这个quorum。
如果没有现成的quorum,并且自己在monmap中,则把peer添加到outside_quorum的集合中。如果此时outside_quorum中的成员大于等于monmap->size() / 2 + 1时,开始选举,否则返回,等待条件满足。 
  Monitor::start_election (),在这里主要做了以下几件事。

如果Paxos正在STATE_WRITING或者STATE_WRITING_PREVIOUS状态,则等待paxos的更新完成。
重置monitor中的服务,包括probe timeout事件、停止时间检查(mon time skew的检查)、health检查事件、scrub事件等,并且restart paxos以及所有的paxos service服务。
设置自己进入STATE_ELECTING状态,并增加l_mon_num_elections和l_mon_election_call这些统计数据。
调用elector的call_election()。 
  Monitor::start_election (),在这里主要做了以下几件事。

从Mon store中读出mon的election_epoch存储在epoch中,更新epoch的值使其变为奇数,表明进入了选举cycle。epoch为偶数,表明已经形成了稳定的quorum。
把自己加入到acked_me map中,并设置electing_me为true,希望大家选自己当leader。
向monmap中的成员发送MMonElection::OP_PROPOSE消息。 
  其它的Monitor收到消息后,经过dispatch逻辑,即Monitor:: ms_dispatch() --> Monitor::_ms_dispatch() --> Monitor::dispatch_op()--> Elector::dispatch(),之后进入消息处理流程。

Elector::handle_propose(),首先确保收到消息的epoch版本是处于选举的版本(奇数)并且满足对feature的要求。接着判断将自己的选举epoch设置为和消息中包含的epoch的值。最后比对rank值,如果自己的rank值更小,则自己不ack此次选举,而是重新发起一轮选举。如果自己的rank值更大,则进入Elector::defer()流程,发送MMonElection::OP_ACK消息,ack该轮选举。
  发起选举的Monitor收到ACK消息之后,进入处理流程:

将ACK自己的peer加入到acked_me这个map中,如果acked_me的个数和monmap中成员的个数一样,则表明选举成功,进入victory流程。这里有点需要搞清楚的是在有一个monitor down的情况下,剩余的monitor是如何选举成功的(acked_me的成员肯定和monmap的成员个数不相等)。
  Leader会进入Elector::victory(),具体处理流程如下:

将acked_me中的成员加入到quorum中,并且将election epoch的值加一使其变成偶数,标志选举过程结束。
向quorum中的所有成员发送MMonElection::OP_VICTORY,消息通知大家选举结束。
告诉monitor自己选举成功。 
  Leader进入Monitor::win_election(),具体处理流程如下:

设置自己的状态为STATE_LEADER,清空outside_quorum中的成员。
调用paxos->leader_init()初始化paxos,以及所有的paxos_service服务。在paxos的初始化中会设置paxos的状态为STATE_RECOVERING,并且调用Paxos::collect()函数,同步mon之间的数据,这个会在后面的Paxos数据更新部分介绍。
启动health_monitor服务,目前主要是检查mon存储空间的使用情况。
启动timecheck检查,确保monitor之间的时差不超过mon_clock_drift_allowed,如果超过就会报告mon clockskew。
更新monitor的metadata,其主要纪录了以下信息:
[root@ceph02 ~]#ceph mon metadata ceph02
{
    "arch": "x86_64",
    "cpu": "Intel Xeon E312xx(Sandy Bridge)",
    "distro": "CentOS",
    "distro_codename":"Core",
    "distro_description":"CentOS Linux release 7.1.1503 (Core) ",
    "distro_version":"7.1.1503",
    "hostname": "ceph02",
    "kernel_description": "#1SMP Tue Sep 15 15:05:51 UTC 2015",
    "kernel_version":"3.10.0-229.14.1.el7.x86_64",
    "mem_swap_kb": "0",
    "mem_total_kb":"1884312",
    "os": "Linux"
}
  Peon在收到MMonElection::OP_VICTORY消息之后进入Elector::handle_victory(),具体处理流程如下:

将自己的election epoch设置成消息中的epoch值。
进入Monitor::lose_election(),设置自己的状态为STATE_PEON,调用peon_init初始化paxos以及相关的paxosservice,更新logger信息。
取消自己的expire_event时间,即有参数mon_election_timeout控制的时间。 
至此,Monitor的选举过程就算结束了,但Paxos的状态还没有进入稳态,所以剩下的事情就是Leader来协调quorum中所有成员的数据同步了,这个主要是通过Paxos协议的两阶段提交机制来完成,整个过程相对比较复杂,会在后续数据更新机制中详细进行介绍。为了方便了解整个选举过程,我将主要的逻辑以时序图的形势展现出来,具体详见下图,图中主要以Leader为主线,给出了选举过程涉及的几个主要文件。


————————————————
原文链接:https://blog.csdn.net/scaleqiao/article/details/52315468

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值