GithubHelp home page GithubHelp logo

Comments (19)

Tomclancysi avatar Tomclancysi commented on May 18, 2024

@LovesAsuna
“conflictIndex赋值到nextIndex也没什么问题” 这对conflictIndex的理解有点问题。
conflictIndex就是指的Follower的log中,在PrevLogIndex的前面 第一个 与 ConflictTerm 不一样的点。
这个信息返回给Leader后,Leader知道他前面有多少个一样的Term了,这样回退nextIndex的时候就相当于知道Follower前面的Log了。

其实如果Follower能够直接把它的Log中的Term都返回给Leader,然后Leader肯定能直接找到回退点,不需要一次RPC回退一下。
而这个机制相当于使用游程编码,使得传输成本更低。

这种方法在冲突Index的term都是一样的情况下比较高效(比如发生了split brain,其中一个小组的leader一直在接受客户端命令,假设1w条,这些命令都是在一个Term中,但是又不会被执行,最终需要网络恢复后删除掉),paper里也说了这不是必要的,但是不实现就通不过test

from mit6.824-2021.

LovesAsuna avatar LovesAsuna commented on May 18, 2024

conflictIndex不就是由follower计算出来的吗?leader用这个计算出来的值不就可以达到快速回退的目的了?

from mit6.824-2021.

Tomclancysi avatar Tomclancysi commented on May 18, 2024

但是leader不一定要回退到conflictIndex,从conflictIndex到PrevLogIndex中,如果有一个点对上了就可以回退到那个点

from mit6.824-2021.

LovesAsuna avatar LovesAsuna commented on May 18, 2024

冲突之后的日志不是要截断?

from mit6.824-2021.

Tomclancysi avatar Tomclancysi commented on May 18, 2024

是的

from mit6.824-2021.

LovesAsuna avatar LovesAsuna commented on May 18, 2024

那follower截断conflictIndex之后的日志,leader直接用conflictIndex作为nextIndex不就可以把日志一次性发给follower了

from mit6.824-2021.

Tomclancysi avatar Tomclancysi commented on May 18, 2024

conflictIndex不等于要回退的位置。
比如Follower的log里有1w个Term为2,而Leader有9999个Term为2的、其他的都是Term为3的,当PrevLogIndex==1w时
在验证第1w个log的时候发现冲突,Follower告诉Leader前面还有多少个Term为2的(conflictIndex=0),然后Leader就在自己的log里面从后往前比较,然后发现第9999个log的Term就是2,然后nextIndex就只用回退一位。

这显然不需要回退到0,那样还得重发这1w条数据。

from mit6.824-2021.

LovesAsuna avatar LovesAsuna commented on May 18, 2024

这里可能是我的理解不一样,在我的实现里是把conflictIndex就设为1w,follower截断1w之后的数据,然后leader设置nextIndex就设为conflictIndex的1w,然后把日志发送给follower

from mit6.824-2021.

Tomclancysi avatar Tomclancysi commented on May 18, 2024

那这样每次rpc只回退一个单位test2B的“leader backs up quickly over incorrect follower logs”可能过不了

from mit6.824-2021.

LovesAsuna avatar LovesAsuna commented on May 18, 2024

不是回退一个单位,就是直接回退到conflictIndex,因为我的设计里conflictIndex不是一个长度,就是一个具体的索引位置

from mit6.824-2021.

LovesAsuna avatar LovesAsuna commented on May 18, 2024

第一个conflictIndex就是冲突位置,第二个则是冲突位置的前一个,这里的设计是否有错误?

这里要怎么理解?

我自己对handleAppendEntries的实现是这样的

https://github.com/LovesAsuna/mit6.5840/blob/75149b6f4e8719ca11cf9b97cc5e326b2e0a80f3/src/raft/raft.go#L621

from mit6.824-2021.

Tomclancysi avatar Tomclancysi commented on May 18, 2024

不需要直接回退到conflictIndex,可以看看这段代码,结合test2B“leader backs up quickly over incorrect follower logs”的Log理解

https://github1s.com/s09g/raft-go/blob/HEAD/src/raft/append_entry.go#L73-L84

from mit6.824-2021.

Tomclancysi avatar Tomclancysi commented on May 18, 2024

主要理解几个问题

  1. conflictIndex不是冲突的位置。Follower都不知道Leader的整个Log,怎么知道这个位置是冲突的?有没有可能这个位置甚至后面一部分Leader不冲突?
  2. conflictIndex说明在[conflictIndex,PrevLogIndex]这段区间内,Follower的Term是相同的
  3. Leader需要判断自身的Log,如果在[conflictIndex,PrevLogIndex]中存在一个Term == ConflictTerm的Index,那必然前面的也相同,回退到Index。否则回退到conflictIndex(就是上面链接那段做的事)

from mit6.824-2021.

LovesAsuna avatar LovesAsuna commented on May 18, 2024

主要是实现不太一样,我参考的是这个仓库owner的实现;我看你的实现是按照课上Robert教授的方法来的(Xterm、XIndex、XLen)。有点不好统一起来,仓库owner没给出handlerAppendEntries的实现,很多东西要边看论文边猜出来

第一个conflictIndex就是冲突位置,第二个则是冲突位置的前一个,这里的设计是否有错误?

这个始终没理解

from mit6.824-2021.

Tomclancysi avatar Tomclancysi commented on May 18, 2024

按自己理解大胆改就完事了,我写的时候也看了别人的,但是最后还是按照我自己的想法实现的,通过testcase说明差不多就对了

from mit6.824-2021.

Tomclancysi avatar Tomclancysi commented on May 18, 2024

不过改的时候不确定的话先记录一下位置,方便后面debug重点看

from mit6.824-2021.

OneSizeFitsQuorum avatar OneSizeFitsQuorum commented on May 18, 2024

image

image

之前应该是按照 介绍 里面的提到的扩展版论文实现的

from mit6.824-2021.

infdahai avatar infdahai commented on May 18, 2024
if !rf.matchLog(args.PrevLogTerm, args.PrevLogIndex) {
    reply.Term, reply.Success = rf.currentTerm, false
    lastIndex := rf.getLastLog().Index
    if lastIndex < args.PrevLogIndex {
        reply.ConflictTerm, reply.ConflictIndex = -1, lastIndex+1
    } else {
        firstIndex := rf.getFirstLog().Index
        reply.ConflictTerm = rf.logs[args.PrevLogIndex-firstIndex].Term
        index := args.PrevLogIndex - 1
        for index >= firstIndex && rf.logs[index-firstIndex].Term == reply.ConflictTerm {
            index--
        }
        reply.ConflictIndex = index
    }
    return
}

这一段中,如果follower与leader的日志不匹配,可以将conflictTerm和conflictIndex给到leader,让leader快速回退到冲突位置,而不需要递减index。这里的两种情况:

  1. follower日志过短,跟不上follower日志
    在这里conflictTerm设置为-1,conflictIndex设置为follower最后一条日志的index+1
  2. 正常的冲突
    这里将conflictTerm只设置为要同步日志的任期,按我的理解,如果已经同步的位置到这个位置中间有有多个不同的任期,这里还是需要进行等同不同任期数量次数的请求才能到同步点的后一个位置
    然后这里我不懂的是这里设置conflictIndex为index,在for循环中,退出条件是term != conflictTerm,当这里已经到同步点后的任期时,这里退出循环时index就会等于同步点的index

这里两种情况,第一个conflictIndex就是冲突位置,第二个则是冲突位置的前一个,这里的设计是否有错误?

另外我想参考一下handleAppendEntriesReply的具体实现,因为我感觉conflictTerm好像并没有起到什么实际作用,可以直接将conflictIndex赋值到nextIndex也没什么问题(按照conflictIndex就是冲突位置的逻辑)

我觉得都可以,使用前一个也能保证正确。处理冲突时只传递confict Index也可以过测试。我的处理就是拿匹配term的第一个index发送的,接收端设置到NextIndex。

if rf.getLastIndex() < args.PrevLogIndex {
		reply.Success = false
		reply.XIndex = rf.getLastIndex()
		// maybe snapshot, so not Adding 1
		// snapshot increase and you should grap this.

		return
	}

	if rf.getLogTermWithIndex(args.PrevLogIndex) != args.PrevLogTerm {
		reply.Success = false
		xTerm := rf.getLogTermWithIndex(args.PrevLogIndex)
		for index := args.PrevLogIndex; index >= rf.lastSnapshotIndex; index-- {
			if rf.getLogTermWithIndex(index) != xTerm {
				reply.XIndex = index + 1
				break
			}
		}
		return
	}

from mit6.824-2021.

OneSizeFitsQuorum avatar OneSizeFitsQuorum commented on May 18, 2024

发送端和接收端只要协调好的话应该有很多种方案的

from mit6.824-2021.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.