news 2026/6/6 10:37:56

分布式一致性算法:Raft

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
分布式一致性算法:Raft

首先,用一个问题引入分布式一致性的概念:如何用多台计算机维持同一份数据?

在分析这个问题之前,可能首先还要回答两个更直观的问题:

  1. 为什么要用多台计算机保持同一份数据?
  2. 从多台计算机读这一份数据的时候,数据是一样的吗?

对于第一个问题,简单分析一下就明白了。因为分布式系统中的节点都有一定的概率发生故障,虽然单个节点的故障概率比较小,但当系统规模不断上升,故障的概率就变大了许多,也即,虽然一台设备很少发生故障,但是当设备规模变大,故障就成了日常。节点的故障会对系统的可用性、可靠性产生影响。当数据在系统中只有一份存储时,如果发生断电、主机crash、网络故障,那么导致的是数据的暂时不可用;如果发生磁盘损坏,则会导致数据丢失,也就是系统不可靠。因此数据冗余(复制集、副本集),即同一分数据在系统中不同节点保存多份,可以有效提高系统的可用性和数据的可靠性。

第二个问题是分布式系统中最复杂的问题之一: 副本的一致性问题,即从系统外部读取系统内部各个副本间的数据在一定的约束条件下是一致的。

为了解决第二个问题,人们提出了很多不同的副本控制协议,即在分布式系统中,按照特定的流程规范来读写副本数据,使得副本满足一定的可用性和一致性的要求。副本控制协议有很多,也有不同的分类标准,比如:同步与异步、强一致性与弱一致性、中心化与去中心化等。

中心化副本控制协议

所谓的中心化,就是对于副本集的更新操作有一个中心节点来协调管理,将分布式的并发操作转化为单点的并发操作,从而保证副本集内各节点的一致性。其优点在于逻辑简单,将复杂的问题(分布式并发)转换成一个有成熟解决方案的问题(单点并发)。但缺点在于,副本集的可用性依赖于中心节点,如果中心节点故障,即使有中心节点自动切换机制,也会出现数10秒的不可用。大多数的分布式存储都会采用中心化副本控制协议,比如GFS、TFS、MongoDB。

而去中心化则是说副本集中没有中心节点,所有节点的地位是平等的,大家都可以接受更新请求,相互通过协商达成数据的一致。去中心化副本控制协议的最大好处在于可用性比较强,只要有大多数节点存活就能提供服务。但缺点是协议流程复杂,尤其是需要强一致性保证的时候。在业界中,Dynamo,cassandra就是基于去中心化协议。

下面主要讨论中心化副本控制协议,从以下方面进行讨论。

  1. 写节点怎么将变更的数据同步到其他节点,同步还是异步;
  2. 非写节点能否提供读数据,如果能够允许,会不会读取到过时的数据。
  3. 主节点是怎么产生的,当主节点宕机的时候,怎么选择出新的主节点。是有统一的复制集管理中心(记录谁主谁次,各自的状态),还是复制集自己选举出一个主节点?

主从节点数据更新流程

第一个问题:复制集之间数据的同步是同步模式还是异步模式

在中心化副本控制协议中,主节点(primary)提供写入操作,数据会同步到其他节点。注意,上面语句中第一个同步是指复制集中节点间数据趋于一致的过程。

所谓同步(Synchronous replication),就是说对于客户端请求,系统阻塞到复制集中所有节点都更新完成,才能向客户端返回,即write all。而异步(Asynchronous replication)模式,只要一个或者部分节点更新则算写入操作成功,通常是write one。

上图(来源于Distributed systems for fun and profit,下同)即为同步模式,客户端的请求被发送到s1这个副本集,s1将请求转发给s2、s3,等s2、s3都操作完成之后再向客户端返回结果。

在同步模式下,系统的可靠性非常好,只要有一个节点正常,就能保证数据不丢失。但是系统的更新可用性非常差,只要有一个节点异常,就无法完成更新;而且,响应延迟比较大,取决于副本集中网络延时最大、处理速度最慢的节点。

上图则是异步模式,客户端的写请求只要在一个节点上完成就立即向客户端返回结果。在上图中,数据被写入到s1即认为写入成功,向客户端返回,系统在后台由s1向s2、s3节点同步数据。异步模式下,系统的吞吐量会比较好,但是存在数据丢失的风险,比如上图中,如果在数据同步到s2和s3之前s1挂掉,那么刚才客户端的更新就丢失了,关键在于客户端认为已经写入成功了。另外,异步模式下,客户端在写入成功之后,立刻从系统读取数据,有可能读不到最新的数据,比如上图中,如果客户端写入s1之后立刻从s2 读取,读取的数据是过期数据。

在数据同步的时候选择同步模式还是异步模式呢,这个取决于系统对一致性、可用性、响应延迟的要求。比如在分布式文件系统GFS中,需要保证复制集内副本的强一致性,而单次读写的响应延迟并没有那么重要,因此选择了同步模式,即primary需要等到所有的secondary都写入成功才会向客户端返回。而在分布式数据库MongoDB中,决定权交给了用户,用户可以决定使用同步模式还是异步模式。

第二个问题,数据的流向,流向有两种,链式与主从模式。

链式就是指从一个节点推送到最近的节点,比如GFS,“最近” 可以用IP地址或者节点间心跳TTL来衡量,如图所示(图片来源于清华阿里-大数据课程的PPT):

链式写入

不难看出,写入过程中每个节点的带宽利用都比较均衡,可以充分利用网络资源,也不会有单点压力;但是需要经过多个节点,写入延迟会比较大。

而主从模式则是指数据同时从primary节点到secondary节点,如图所示(来源

默认情况下MongoDB也是采用的链式模式,但是可以通过设置settings.chainingAllowed= false 来采用主从模式。在主从模式下,Secondary会从Primary拉取OPLOG并应用到本地。显然,在这种模式下Primary节点的带宽压力比较大,但是写入延迟会小一些。

第三个问题:主从节点数据读取

复制集中,不同的系统在数据读取方面有两个问题。第一:secondary节点是否提供读服务;第二,如果可以从Secondary读取,那么这个接口是否开放给用户。

第一个问题,如果secondary节点提供数据读取服务,那么是否会读取到过期的数据(即不是最新成功写入的数据)?比如在异步写入的时候,客户端得到成功写入的返回之后,立即去secondary上读取,那么有可能读到过时的数据,这对于强一致性的情况是不能允许的。我们知道,元数据的管理一般也是复制集,而元数据需要保证强一致性,因此,元数据的写入一般都是同步的。比如GFS中,master由一个active(也就是primary节点)、多个standby(也就是secondary节点)组成,在元数据写入到active的时候,要保证本地和远程机器都写入成功才能返回;而且只有active提供读取服务。

第二个问题,如果复制集中的节点都能提供读取服务,那么接口是否提供给最终用户呢?在haystack中,多个在不同机器上的物理卷组成一个逻辑卷,一个逻辑卷就是一个复制集。当读取请求到达的时候,是由haystack的元数据服务器(directory)根据负载均衡的原则选出提供服务的物理卷,即用户是不知道读取请求是落地到哪个物理节点的。而对于mongodb,用户可以在查询语句里面指定是从Primary读取,还是从Secondary读取,或者让系统来选择(Nearest)。

主节点选举

在中心化副本控制协议中,这个中心(primary)是怎么选出来的呢?是上级指定还是民主选举呢?

GFS系统中,Primary节点是由master(GFS中的元数据服务器)通过lease机制选择的,简单说来,GFS给某个节点颁发Lease,该节点就成为了Primary节点,Primary节点也可以在过期之前重新申请Lease,而且Lease的颁发、申请信息都是在chunkserver与master的心跳中,因此也不会带来过多额外的开销。使用Lease机制能很好的避免在复制集中出现双主(同时有两个节点认为自己是Primary)现象。

而在Zookeeper、TFS、MongoDB中,都是通过去中心化的协议选举出Primary节点,选举出Primary节点之后,就变成了中心化的副本控制协议,当Primary出现故障之后,会重新选举过程。对于民主选举,两个因素非常重要:第一是强一致性,只能选举出一个Primary;第二个是可用性,选举过程要越快越好。

为了达到强一致性,需要使用分布式一致性协议,目前较为常见的协议有Paxos协议,该协议可以实现所有备份均可以提供对外服务,并且保证强一致性,通过理论和实践检验可以达到分布式的要求。Raft协议则是Paxos的一种特化,在这个协议的实现中,备份间需要区分主从角色,只有主节点可以提供对外服务,协议实现简单高效,能很容易的同各种分布式数据一致性同步场景相结合,是工程实现最好的选择。


raft是工程上使用较为广泛的强一致性、去中心化、高可用的分布式协议。在这里强调了是在工程上,因为在学术理论界,最耀眼的还是大名鼎鼎的Paxos。但Paxos是:少数真正理解的人觉得简单,尚未理解的人觉得很难,大多数人都是一知半解。raft的论文中,两位研究者也提到,他们也花了很长的时间来理解Paxos,但是也觉得很难理解,认真理解了一年之后,研究出了raft算法。

raft是一个共识算法(consensus algorithm),所谓共识,就是多个节点对某个事情达成一致的看法,即使是在部分节点故障、网络延时、网络分割的情况下也能完成。去中心化的加密货币区块链也需要共识算法。和区块链需要考虑恶意节点的情况不同,在分布式系统中,共识算法更多用于提高系统的容错性,比如分布式存储中的复制集(replication),raft协议是一种leader-based的共识算法。

raft算法概览

Raft算法的头号目标就是容易理解,这从论文的标题(Raft.Understandable Distributed Consensus)就可以看出来。当然,Raft增强了可理解性,在性能、可靠性、可用性方面是不输于Paxos的。

Raft more understandable than Paxos and also provides a better foundation for building practical systems

为了达到易于理解的目标,raft做了很多努力,其中最主要是两件事情:

  • 问题分解
  • 状态简化

问题分解是将"复制集中节点一致性"这个复杂的问题划分为数个可以被独立解释、理解、解决的子问题。在raft,子问题包括,leader electionlog replicationsafetymembership changes。而状态简化更好理解,就是对算法做出一些限制,减少需要考虑的状态数,使得算法更加清晰,更少的不确定性(比如,保证新选举出来的leader会包含所有commited log entry)

Raft implements consensus by first electing a distinguished leader, then giving the leader complete responsibility for managing the replicated log. The leader accepts log entries from clients, replicates them on other servers, and tells servers when it is safe to apply log entries to their state machines. A leader can fail or become disconnected from the other servers, in which case a new leader is elected.

上面的引文对raft协议的工作原理进行了高度的概括:raft会先选举出leader,leader完全负责replicated log的管理。leader负责接受所有客户端更新请求,然后复制到follower节点,并在“安全”的时候执行这些请求。如果leader故障,followers会重新选举出新的leader。

这就涉及到raft最新的两个子问题: leader election和log replication

leader election

raft协议中,一个节点任一时刻处于以下三个状态之一:

  • leader
  • follower
  • candidate

给出状态转移图能很直观的直到这三个状态的区别

可以看出所有节点启动时都是follower状态;在一段时间内如果没有收到来自leader的心跳,从follower切换到candidate,发起选举;如果收到majority的造成票(含自己的一票)则切换到leader状态;如果发现其他节点比自己更新,则主动切换到follower。

总之,系统中最多只有一个leader,如果在一段时间里发现没有leader,则大家通过选举-投票选出leader。leader会不停的给follower发心跳消息,表明自己的存活状态。如果leader故障,那么follower会转换成candidate,重新选出leader。

term

从上面可以看出,哪个节点做leader是大家投票选举出来的,每个leader工作一段时间,然后选出新的leader继续负责。这根民主社会的选举很像,每一届新的履职期称之为一届任期,在raft协议中,也是这样的,对应的术语叫term

term(任期)以选举(election)开始,然后就是一段或长或短的稳定工作期(normal Operation)。从上图可以看到,任期是递增的,这就充当了逻辑时钟的作用;另外,term 3展示了一种情况,就是说没有选举出leader就结束了,然后会发起新的选举,后面会解释这种split vote的情况。

选举过程详解

上面已经说过,如果follower在election timeout内没有收到来自leader的心跳,(也许此时还没有选出leader,大家都在等;也许leader挂了;也许只是leader与该follower之间网络故障),则会主动发起选举。步骤如下:

  • 增加节点本地的current term,切换到candidate状态
  • 投自己一票
  • 并行给其他节点发送RequestVote RPCs
  • 等待其他节点的回复

在这个过程中,根据来自其他节点的消息,可能出现三种结果

  1. 收到majority的投票(含自己的一票),则赢得选举,成为leader
  2. 被告知别人已当选,那么自行切换到follower
  3. 一段时间内没有收到majority投票,则保持candidate状态,重新发出选举

第一种情况,赢得了选举之后,新的leader会立刻给所有节点发消息,广而告之,避免其余节点触发新的选举。在这里,先回到投票者的视角,投票者如何决定是否给一个选举请求投票呢,有以下约束:

  • 在任一任期内,单个节点最多只能投一票
  • 候选人知道的信息不能比自己的少(这一部分,后面介绍log replication和safety的时候会详细介绍)
  • first-come-first-served 先来先得

第二种情况,比如有三个节点A B C。A B同时发起选举,而A的选举消息先到达C,C给A投了一票,当B的消息到达C时,已经不能满足上面提到的第一个约束,即C不会给B投票,而A和B显然都不会给对方投票。A胜出之后,会给B,C发心跳消息,节点B发现节点A的term不低于自己的term,知道有已经有Leader了,于是转换成follower。

第三种情况,没有任何节点获得majority投票,比如下图这种情况:

总共有四个节点,Node C、Node D同时成为了candidate,进入了term 4,但Node A投了NodeD一票,NodeB投了Node C一票,这就出现了平票 split vote的情况。这个时候大家都在等啊等,直到超时后重新发起选举。如果出现平票的情况,那么就延长了系统不可用的时间(没有leader是不能处理客户端写请求的),因此raft引入了randomized election timeouts来尽量避免平票情况。同时,leader-based 共识算法中,节点的数目都是奇数个,尽量保证majority的出现。

log replication

当有了leader,系统应该进入对外工作期了。客户端的一切请求来发送到leader,leader来调度这些并发请求的顺序,并且保证leader与followers状态的一致性。raft中的做法是,将这些请求以及执行顺序告知followers。leader和followers以相同的顺序来执行这些请求,保证状态一致。

Replicated state machines

共识算法的实现一般是基于复制状态机(Replicated state machines),何为复制状态机:

If two identical,deterministicprocesses begin in the same state and get the same inputs in the same order, they will produce the same output and end in the same state.

简单来说:相同的初识状态 + 相同的输入 = 相同的结束状态。引文中有一个很重要的词deterministic,就是说不同节点要以相同且确定性的函数来处理输入,而不要引入一下不确定的值,比如本地时间等。如何保证所有节点get the same inputs in the same order,使用replicated log是一个很不错的注意,log具有持久化、保序的特点,是大多数分布式系统的基石。

因此,可以这么说,在raft中,leader将客户端请求(command)封装到一个个log entry,将这些log entries复制(replicate)到所有follower节点,然后大家按相同顺序应用(apply)log entry中的command,则状态肯定是一致的。

下图形象展示了这种log-based replicated state machine​​​​​​​

请求完整流程

当系统(leader)收到一个来自客户端的写请求,到返回给客户端,整个过程从leader的视角来看会经历以下步骤:

  • leader append log entry
  • leader issue AppendEntries RPC in parallel
  • leader wait for majority response
  • leader apply entry to state machine
  • leader reply to client
  • leader notify follower apply log

可以看到日志的提交过程有点类似两阶段提交(2PC),不过与2PC的区别在于,leader只需要大多数(majority)节点的回复即可,这样只要超过一半节点处于工作状态则系统就是可用的。

那么日志在每个节点上是什么样子的呢

不难看到,logs由顺序编号的log entry组成 ,每个log entry除了包含command,还包含产生该log entry时的leader term。从上图可以看到,五个节点的日志并不完全一致,raft算法为了保证高可用,并不是强一致性,而是最终一致性,leader会不断尝试给follower发log entries,直到所有节点的log entries都相同。

在上面的流程中,leader只需要日志被复制到大多数节点即可向客户端返回,一旦向客户端返回成功消息,那么系统就必须保证log(其实是log所包含的command)在任何异常的情况下都不会发生回滚。这里有两个词:commit(committed),apply(applied),前者是指日志被复制到了大多数节点后日志的状态;而后者则是节点将日志应用到状态机,真正影响到节点状态。

The leader decides when it is safe to apply a log entry to the state machines; such an entry is called committed. Raft guarantees that committed entries are durable and will eventually be executed by all of the available state machines. A log entry is committed once the leader that created the entry has replicated it on a majority of the servers

safety

在上面提到只要日志被复制到majority节点,就能保证不会被回滚,即使在各种异常情况下,这根leader election提到的选举约束有关。在这一部分,主要讨论raft协议在各种各样的异常情况下如何工作的。

衡量一个分布式算法,有许多属性,如

  • safety:nothing bad happens,
  • liveness: something good eventually happens.

在任何系统模型下,都需要满足safety属性,即在任何情况下,系统都不能出现不可逆的错误,也不能向客户端返回错误的内容。比如,raft保证被复制到大多数节点的日志不会被回滚,那么就是safety属性。而raft最终会让所有节点状态一致,这属于liveness属性。

raft协议会保证以下属性

Election safety

选举安全性,即任一任期内最多一个leader被选出。这一点非常重要,在一个复制集中任何时刻只能有一个leader。系统中同时有多余一个leader,被称之为分裂( split),这是非常严重的问题,会导致数据的覆盖丢失。在raft中,两点保证了这个属性:

  • 一个节点某一任期内最多只能投一票;
  • 只有获得majority投票的节点才会成为leader。

因此,某一任期内一定只有一个leader

log matching

很有意思,log匹配特性, 就是说如果两个节点上的某个log entry的log index相同且term相同,那么在该index之前的所有log entry应该都是相同的。如何做到的?依赖于以下两点

  • If two entries in different logs have the same index and term, then they store the same command.
  • If two entries in different logs have the same index and term, then the logs are identical in all preceding entries.

首先,leader在某一term的任一位置只会创建一个log entry,且log entry是append-only。其次,consistency check。leader在AppendEntries中包含最新log entry之前的一个log 的term和index,如果follower在对应的term index找不到日志,那么就会告知leader不一致。

在没有异常的情况下,log matching是很容易满足的,但如果出现了node crash,情况就会变得复杂。比如下图

注意:上图的a-f不是6个follower,而是某个follower可能存在的六个状态

leader、follower都可能crash,那么follower维护的日志与leader相比可能出现以下情况

  • 比leader日志少,如上图中的ab
  • 比leader日志多,如上图中的cd
  • 某些位置比leader多,某些日志比leader少,如ef(多少是针对某一任期而言)

为什么会出现上面这些不同呢?对于比leader日志少的情况比较容易理解,可能是出于网络故障,节点没有收到leader发出的appendEntry的消息;对于比leader多的情况,可能是由于该节点曾经当选过leader,但是它还没有来得及把自己收到的命令发布出去,就已经挂了,所以只有它自己保存了这些消息;对于ef的情况,可能是在term 2和term 3中,节点曾经当选,并收到一些命令,但是还没有来得及发出appendEntry的消息,它就down了,然后一直down到term 8,才重新加入。但是,term 8中leader的数据,还是受到了大部分节点的支持的。

当出现了leader与follower不一致的情况,leader强制follower复制自己的log

To bring a follower’s log into consistency with its own, the leader must find the latest log entry where the two logs agree, delete any entries in the follower’s log after that point, and send the follower all of the leader’s entries after that point.

leader会维护一个nextIndex[]数组,记录了leader可以发送每一个follower的log index,初始化为eader最后一个log index加1, 前面也提到,leader选举成功之后会立即给所有follower发送AppendEntries RPC(不包含任何log entry, 也充当心跳消息),那么流程总结为:

step 1 leader 初始化nextIndex[x]为 leader最后一个log index + 1
step 2 AppendEntries里prevLogTerm prevLogIndex来自 logs[nextIndex[x] - 1]
step3 如果follower判断prevLogIndex位置的log term不等于prevLogTerm,那么返回 False,否则返回True
step 4 leader收到follower的回复,如果返回值是False,则nextIndex[x] -= 1, 跳转到step2. 否则
step 5 同步nextIndex[x]后的所有log entries

leader completeness vs elcetion restriction

leader完整性:如果一个log entry在某个任期被提交(committed),那么这条日志一定会出现在所有更高term的leader的日志里面。这个跟leader election、log replication都有关。

  • 一个日志被复制到majority节点才算committed
  • 一个节点得到majority的投票才能成为leader,而节点A给节点B投票的其中一个前提是,B的日志不能比A的日志旧。下面的引文指处了如何判断日志的新旧
voter denies its vote if its own log is more up-to-date than that of the candidate.
If the logs have last entries with different terms, then the log with the later term is more up-to-date. If the logs end with the same term, then whichever log is longer is more up-to-date.

上面两点都提到了majority:commit majority and vote majority,根据Quorum,这两个majority一定是有重合的,因此被选举出的leader一定包含了最新的committed的日志。

raft与其他协议(Viewstamped Replication、mongodb)不同,raft始终保证leader包含最新的已提交的日志,因此leader不会从follower catchup日志,这也大大简化了系统的复杂度。

corner case

stale leader

raft保证Election safety,即一个任期内最多只有一个leader,但在网络分割(network partition)的情况下,可能会出现两个leader,但两个leader所处的任期是不同的。如下图所示

系统有5个节点ABCDE组成,在term1,Node B是leader,但Node A、B和Node C、D、E之间出现了网络分割,因此Node C、D、E无法收到来自leader(Node B)的消息,在election time之后,Node C、D、E会分期选举,由于满足majority条件,Node E成为了term 2的leader。因此,在系统中貌似出现了两个leader:term 1的Node B, term 2的Node E, Node B的term更旧,但由于无法与Majority节点通信,NodeB仍然会认为自己是leader。

在这样的情况下,我们来考虑读写。

首先,如果客户端将请求发送到了Node B,Node B无法将log entry 复制到majority节点,因此不会告诉客户端写入成功,这就不会有问题。

对于读请求,stale leader可能返回stale data,比如在read-after-write的一致性要求下,客户端写入到了term 2任期的leader Node E,但读请求发送到了Node B。如果要保证不返回stale data,leader需要check自己是否过时了,办法就是与大多数节点通信一次,这个可能会出现效率问题。另一种方式是使用lease,但这就会依赖物理时钟。

从raft的论文中可以看到,leader转换成follower的条件是收到来自更高term的消息,如果网络分割一直持续,那么stale leader就会一直存在。而在raft的一些实现或者raft-like协议中,leader如果收不到majority节点的消息,那么可以自己step down,自行转换到follower状态。

State Machine Safety

前面在介绍safety的时候有一条属性没有详细介绍,那就是State Machine Safety:

State Machine Safety: if a server has applied a log entry at a given index to its state machine, no other server will ever apply a different log entry for the same index.

如果节点将某一位置的log entry应用到了状态机,那么其他节点在同一位置不能应用不同的日志。简单点来说,所有节点在同一位置(index in log entries)应该应用同样的日志。但是似乎有某些情况会违背这个原则:

上图是一个较为复杂的情况。在时刻(a), s1是leader,在term2提交的日志只复制到了s1 s2两个节点就crash了。在时刻(b), s5成为了term 3的leader,日志只复制到了s5,然后crash。然后在(c)时刻,s1又成为了term 4的leader,开始复制日志,于是把term 2的日志复制到了s3,此刻,可以看出term 2对应的日志已经被复制到了majority,因此是committed,可以被状态机应用。不幸的是,接下来(d)时刻,s1又crash了,s5重新当选,然后将term 3的日志复制到所有节点,这就出现了一种奇怪的现象:被复制到大多数节点(或者说可能已经应用)的日志被回滚。

究其根本,是因为term 4时的leader s1在(C)时刻提交了之前term 2任期的日志。如何理解呢?如果S1不是只提交2,而是连同最新的日志4一起提交了,这样的话,有三个节点的日志到达了term 4,那么接下来S5就不会当选,也不会出现日志回滚的情况。

因此,为了杜绝这种情况的发生:

Raft never commits log entries from previous terms by counting replicas.
Only log entries from the leader’s current term are committed by counting replicas; once an entry from the current term has been committed in this way, then all prior entries are committed indirectly because of the Log Matching Property.

也就是说,某个leader选举成功之后,不会直接提交前任leader时期的日志,而是通过提交当前任期的日志的时候“顺手”把之前的日志也提交了。那么问题来了,如果leader被选举后没有收到客户端的请求呢,论文中有提到,在任期开始的时候发立即尝试复制,提交一条空的log

Raft handles this by having each leader commit a blank no-op entry into the log at the start of its term.

因此,在上图中,不会出现(C)时刻的情况,即term4任期的leader s1不会复制term2的日志到s3。而是如同(e)描述的情况,通过复制-提交 term4的日志顺便提交term2的日志。如果term 4的日志提交成功,那么term 2的日志也一定提交成功,此时即使s1 crash,s5也不会当选。

leader crash

follower的crash处理方式相对简单,leader只要不停的给follower发消息即可。当leader crash的时候,事情就会变得复杂。在这篇文章中,作者就给出了一个更新请求的流程图。


我们可以分析leader在任意时刻crash的情况,有助于理解raft算法的容错性。

总结

raft将共识问题分解成两个相对独立的问题,leader election,log replication。流程是先选举出leader,然后leader负责复制、提交log(log中包含command)

为了在任何异常情况下系统不出错,即满足safety属性,对leader election,log replication两个子问题有诸多约束

leader election约束:

  • 同一任期内最多只能投一票,先来先得
  • 选举人必须比自己知道的更多(比较term,log index)

log replication约束:

  • 一个log被复制到大多数节点,就是committed,保证不会回滚
  • leader一定包含最新的committed log,因此leader只会追加日志,不会删除覆盖日志
  • 不同节点,某个位置上日志相同,那么这个位置之前的所有日志一定是相同的
  • Raft never commits log entries from previous terms by counting replicas.
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/6 10:37:50

AI辅助开发:让快马智能诊断并修复你的chromedriver版本兼容性问题

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容: 请生成一个AI辅助的浏览器自动化环境诊断与修复工具。该工具应包含以下智能功能:第一,自动扫描系统环境,识别已安装的Chrome浏览器版本、现有ch…

作者头像 李华
网站建设 2026/6/6 10:36:11

不止于ScanNet:5大主流RGB-D数据集横向评测,你的3D视觉项目该选谁?

主流RGB-D数据集深度评测:如何为3D视觉项目选择最佳数据源当你在深夜的实验室里调试第37个模型版本时,突然意识到——数据质量可能比算法本身更影响最终效果。RGB-D数据集作为3D视觉研究的基石,其选择往往决定了项目80%的上限。本文将带你深入…

作者头像 李华
网站建设 2026/6/6 10:31:02

大模型原生工具调用与上下文持久化:Prompt工程正在蒸发

1. 项目概述:这不是一次普通更新,而是一次架构级“蒸发”“Anthropic Just Shipped the Layer That’s Already Going to Zero”——这个标题一出来,我在 Slack 里看到好几个做 LLM 应用架构的同行直接暂停了手头的 API 调优,转头…

作者头像 李华
网站建设 2026/6/6 10:29:03

内网渗透-横向移动-IPC配合计划任务(schtasks)和系统服务横向移动(sc)

IPC配合计划任务横向移动IPC$介绍IPC( Internet ProcessConnection)共享“命名管道”的资源,是为了实现进程间通信而开放的命名管道。IPC可以通过验证用户名和密码获得相应的权限,通常在远程管理计算机和查看计算 机的共享资源时使用。通过ipc$,可以与目标机器建立连接。利用这…

作者头像 李华