You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@rocketmq.apache.org by GitBox <gi...@apache.org> on 2020/05/31 06:24:30 UTC

[GitHub] [rocketmq] zhangyixin1222 edited a comment on issue #2056: Issues and Improvement Strategies in the Raft Protocol Election

zhangyixin1222 edited a comment on issue #2056:
URL: https://github.com/apache/rocketmq/issues/2056#issuecomment-636428598


   > > 可以在pre-vote基础上对raft做进一步改进以对选举过程中产生的消耗做相关优化,在pre-vote阶段根据自身接受日志记录的term及日志index作为获取选举资格的凭证,但在每次选举中携带自身【termLoged,indexLogged,termWanted,nodeId】拉取选票,其中termLoged为自身接受日志记录的最新term,indexLodded为自身接受最大term日志记录的最大index,termWanted初始值为termLoged,在每次选举失败后+1,nodeId为自身结点,拉取选票会出现以下几种情况:
   > > 【
   > > 情况1:其他结点(如结点B)收到选举消息后经过对比发现结点B自身记录的日志term>结点A发送过来的termLoged,则反馈termSmallError异常的反对票.
   > > 情况2:其他结点(如结点B)收到选举消息后发现自身记录日志term小于结点A发送过来的termLogged,或者自身记录日志term=结点A发送过来的termLogged且自身日志index<indexLogged则更新自身记录的termWanted并反馈以赞同票。
   > > 情况3:其他结点(如节点B)发现自身记录日志term与A发过来的termLogged一致且自身日志index=indexLogged,则以跟自身已认可的termWanted与接受到的termWanted进行对比,如果自身已认可的termWanted>=B结点发过来的termWanted,则反馈选举失败(但不为反对票)并在反馈报文中告知自身记录的最大termWanted。
   > > 】
   > > 结点A根据获取到的多数反馈或经过一定超时时间后根据不同情况分别做如下策略:
   > > 【
   > > 情况1:如果结点A获得了多数结点的认可并未获得反对票,则以leader身份并以termWanted作为任期开始执行leader责任(如果任期失败则再次进入leader查找及选主状态)。
   > > 情况2:如果结点A如果未收到反对票也未获得大多数认可时则据反馈的termWanted集合中与自身(termWanted+1)的最大值来变更termWanted并在随机等待后进行下一轮选票拉取。
   > > 情况3:如果收到的投票中存在反对票,结点B会随机等待后再次判断leader是否存在及在无法知晓leader存在后经过pre-vote阶段获取自身候选人资格并判断是否存在新leader,如果不存在新leader则尝试通过pre-vote获取候选人资格并在候选人资格获得后重新发起选举(之所以如此设计是因为当结点B等少数结点是所有结点中唯一持有更大termLogged的结点并在此后因为这系列少数结点故障永久性无法通信);
   > > 】
   > > 通过以上方案,避免了每次拉选票之前频繁的pre-vote中候选人资格认证阶段的消耗,并能够在获取到leader存在后及时变更自身状态,也保证了当选的leader确实拥有最新的日志记录,同时避免了出现长时间脑裂的恢复后日志term落后引发的误选及有效日志回滚,也避免了少部分记录有最新日志记录结点(因为某些原因日志未受多数认可而leader故障引发无主)集体永久性宕机后引发的无法选举问题。为了保证特殊情况下的及时获取leader信息日志,仍补充issue中所提到的策略
   > 
   > 两个小问题:
   > 自身记录日志term 就是 termLoged 嘛。可以问一下为什么要拆分出term 和 termWanted 嘞,因为您说
   > 
   > > termLoged,indexLogged,termWanted,nodeId】拉取选票,其中termLoged为自身接受日志记录的最新term,indexLodded为自身接受最大term日志记录的最大index,termWanted初始值为termLoged,在每次选举失败后+1,nodeId为自身结点
   > 
   > 如果是这样的话那我理解您定义的
   > 
   > termLoged 相当于dledger里的lastLogTerm,termWanted 相当于 dledger里的term。
   > 
   > 实际上如果每个node都只有一个的term值的话维护起来会方便一点,状态没那么复杂。
   
   对,这部分是你理解的,跟raft协议一致,之所以引入两个不同term是为了当以失败自增的选举term拉取选票前提下保障当选为leader具有全局可见的最新日志纪录。我所提及的变更是对pre-vote这个阶段在选举失败后的重复认可(对第一次pre-vote获取选举人资格及第一次拉取选票这些步骤及之前都未做改动),为了弥补期间出现的间歇性脑裂带来的日志纪录延滞造成的候选人资格剥夺未知问题(因为脑裂期间确实存在着leader已当选问题),在正式选取拉取选票时携带自身最新日志纪录term做对比可以修复该问题。但不管哪种方案,都无法消除该issue所提及的问题(因少部分结点认可过更大的选举term导致当选leader所广播消息暂时不受自身认可(虽然可以在新一轮的比较日志纪录term后会重新正确认可其leader权))。(所涉及的讨论都以在网络或硬件在不同阶段及不同结点可能出现各种问题下如何加速选举及在不丢失历史日志纪录前提下保证最快的一致性恢复,所论述基础抛开上帝视角)。当然,正如raft协议所提及,非选举状态每个结点都只维持一个term,在进入无法获知leader则根据该term分化出日志term及失败自增的选举term。因为容易证明(非选举状态维护两个term会带来连续两次leader故障所引发的其他问题)


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org