美文网首页
RAFT日志连续性思考

RAFT日志连续性思考

作者: 飞哈飞 | 来源:发表于2024-07-18 11:33 被阅读0次

日志保证连续的好处

保证状态一致性

对于增量操作日志,连续顺序保证最终的结果正确性

简化日志一致性检查

确定某一个索引日志是一致的,这个日志的下一个有冲突即可保证这个日志之前都是一致的,不然不保证连续需要逐个比较。
领导选举时需要选择日志完整性最好的节点,如果日志不连续,一个123。一个124将无法判断哪个日志完整性很好,所以要么是123,要么是1234这样,只需比较谁的索引和任期更大即可,实现起来更简单高效。

简化日志恢复

日志主从恢复时确定某一个索引日志是一致的,这个日志的下一个有冲突即可保证这个日志之前都是完整的,只需要截断恢复这个日志后的内容即可,不然如果日志不连续,需要逐个比较

简化代码实现

用数组即可实现,便于索引定位,代码更简洁遍历

如何保证日志是连续的

主节点按顺序写日志没啥难度

同步从节点时需要注意,从节点需要判断主节点来的日志和自己本地的日志是否能连续接上,可以理解同步日志不是简单告诉从节点复制哪些日志,而是说把哪几条日志接在哪一条日志后面来保证从节点也和主节点一样日志是连续的,具体实现代码可以查看etcd的源代码部分,查看log.go里的maybeAppend方法

// maybeAppend returns (0, false) if the entries cannot be appended. Otherwise,
// it returns (last index of new entries, true).
func (l *raftLog) maybeAppend(index, logTerm, committed uint64, ents ...pb.Entry) (lastnewi uint64, ok bool) {
    //index,logTerm是需要复制的新日志信息的上一条日志的信息,比如需要复制索引4,这个则为日志3
    //如果日志3从节点这里不存或者不匹配就会直接发回false了,这里保证了复制新日志的时候上一个日志在从节点这里是和主节点一致的
    //保证了主从节点复制日志的时候连续一致性,只要主节点自己发的日志是连续的,从节点这里也肯定是连续的了  
    //可以理解同步日志不是简单告诉从节点复制哪些日志,而是说把哪几条日志接在哪一条日志后面来保证主从日志一致性
    if l.matchTerm(index, logTerm) {
         //这里也是以日志连续性为基础进行计算,日志连续简化代码实现
        lastnewi = index + uint64(len(ents))
        //验证需要复制的新日志里有没有冲突
        ci := l.findConflict(ents)
        switch {
        //0 表示没有新日志需要复制
        case ci == 0:
        //表示在从节点已提交的日志里有和主节点不一致的,数据有冲突
        case ci <= l.committed:
            l.logger.Panicf("entry %d conflict with committed entry [committed(%d)]", ci, l.committed)
      //表示有新的日志需要复制,就会取ci后的数据来进行复制
        default:
            offset := index + 1
            l.append(ents[ci-offset:]...)
        }
//恢复数据时可能主节点的commit大于发来的日志最大索引
//正常复制时commit是<=发来的日志最大索引的
//因此取最小值进行提交
        l.commitTo(min(committed, lastnewi))
        return lastnewi, true
    }
    return 0, false
}

查看findConflict源码,原版注释很清楚了,不再赘述

// findConflict finds the index of the conflict.
// It returns the first pair of conflicting entries between the existing
// entries and the given entries, if there are any.
// If there is no conflicting entries, and the existing entries contains
// all the given entries, zero will be returned.
// If there is no conflicting entries, but the given entries contains new
// entries, the index of the first new entry will be returned.
// An entry is considered to be conflicting if it has the same index but
// a different term.
// The index of the given entries MUST be continuously increasing.
func (l *raftLog) findConflict(ents []pb.Entry) uint64 {
    for _, ne := range ents {
        if !l.matchTerm(ne.Index, ne.Term) {
            if ne.Index <= l.lastIndex() {
                l.logger.Infof("found conflict at index %d [existing term: %d, conflicting term: %d]",
                    ne.Index, l.zeroTermOnErrCompacted(l.term(ne.Index)), ne.Term)
            }
            return ne.Index
        }
    }
    return 0
}

相关文章

  • 学习 java raft - atmoix

    什么是 raft 日志复制 http://thesecretlivesofdata.com/raft/ 1: cl...

  • raft一致性协议

    raft是一个用于管理复制日志的协议,raft首先先选举出一个leader,然后由leader完全管理复制日志,以...

  • 对标Eureka的AP一致性,Nacos如何实现Raft算法

    一、快速了解Raft算法 Raft 适用于一个管理日志一致性的协议,相比于 Paxos 协议 Raft 更易于理解...

  • Raft精华

    基础 Raft是管理复制日志的一致性算法Raft基于Leader,Follow各个机器上,日志一致了,状态就一致了...

  • Raft(Ver 1.1)

    准备花一星期快速看下Raft Raft是什么 Raft 是一种为了管理复制日志的一致性算法。和Paxos算法有着一...

  • 共识算法 - Raft算法

    1. 什么是 Raft 算法 Raft 是一种为了管理复制日志的共识算法。这个日志可以理解为一个比喻,相当于一个指...

  • RAFT算法

    RAFT算法: RAFT算法引用原文论文翻译的第一句话:RAFT是一种为了管理复制日志的一致性算法(https:/...

  • 共识算法raft的关键概念

    从etcd源码里看raft raft 算法主要有两个过程:一个过程是领导者选举,另一个过程是日志复制,其中日志复制...

  • raft论文笔记

    raft论文笔记 使用目的:Raft 算法是可以用来替代 Paxos 算法的分布式一致性算法,是用来管理复制日志(...

  • 分布式选举-Raft算法-1 Leader选举 原理

    Raft理论是分布式数据一致性算法,为了便于理解Raft算法分成了4个部分:-Leader选举-日志复制-成员变更...

网友评论

      本文标题:RAFT日志连续性思考

      本文链接:https://www.haomeiwen.com/subject/uwerhjtx.html