我看到test中使用了commitNoopEntry(r, s)函数,
有一句 s.Append(r.RaftLog.unstableEntries())
此时这个noop 包被append到storage里,
同时log.entries里仍存在这个包,我该在entries里删掉它吗,
还是说保留并且修改raftlog.Lastindex函数重新计算这个值
1 个赞
应该不用吧,append 之后已经更新 raft log 的 stabled 字段了。不会重复存储这条数据。
1 个赞
我的理解是不需要删除entries中的东西,首先是paper里有提到Leader是Append-Only的,它在启动时也是把storage中的entries都写入log中,我认为是直接更改index就好
1 个赞
下面是etcd 的部分代码
从代码中的最后几行能看到,log 被 append 到了 r.Raftlog.storage 中,但 r.raftlog.entris 仍保留了 log
raftlog.entries 中的则在 stableto 函数中完成删除.
func commitNoopEntry(r *raft, s *MemoryStorage) {
if r.state != StateLeader {
panic("it should only be used when it is the leader")
}
r.bcastAppend()
// simulate the response of MsgApp
msgs := r.readMessages()
for _, m := range msgs {
if m.Type != pb.MsgApp || len(m.Entries) != 1 || m.Entries[0].Data != nil {
panic("not a message to append noop entry")
}
r.Step(acceptAndReply(m))
}
// ignore further messages to refresh followers' commit index
r.readMessages()
s.Append(r.raftLog.unstableEntries())
r.raftLog.appliedTo(r.raftLog.committed)
r.raftLog.stableTo(r.raftLog.lastIndex(), r.raftLog.lastTerm())
}
func (l *raftLog) stableTo(i, t uint64) { l.unstable.stableTo(i, t) }
func (u *unstable) stableTo(i, t uint64) {
gt, ok := u.maybeTerm(i)
if !ok {
return
}
// if i < offset, term is matched with the snapshot
// only update the unstable entries if term is matched with
// an unstable entry.
if gt == t && i >= u.offset {
u.entries = u.entries[i+1-u.offset:]
u.offset = i + 1
u.shrinkEntriesArray()
}
}
但 tinykv 似乎并未提供类似接口
3 个赞
不用删除的,append到storage的日志知识进行了持久化,目的是如果节点crash了可以保存之前的状态,和RaftLog本身需要继续持有日志进行Raft的继续是不矛盾的。
这部分日志无论是否删除,对节点的同步都不会照成影响,etcd删除应该是出于节省内存之类的考虑?
主要是stable了的log未必是正确的日志,比如一种情况:出现网络分区以后,旧Leader被分到了少数区域,他会不断得到日志,然后他的日志也会被stable。但是这些日志都不会被commit以及apply。 多数分区的新Leader的日志才是正确的日志,网络分区结束以后,老Leader需要落选,并且他的日志需要全部被drop掉,包括stable的日志
1 个赞
十分感谢你的回复,你的回复对我的帮助很大.
1 个赞
此话题已在最后回复的 1 分钟后被自动关闭。不再允许新回复。