文章阅读页通栏

Raft共识深度解析与在Hyperledger Fabric中实现Raft共识

来源: 区块链研究实验室 作者:链三丰
Raft是在1.4.1版的基于Kafka和Solo的ordering系统之后推出的共识插件。Raft为ordering服务带来了额外的功能,使生产系统就绪。在开始ordering服务之前,让我们首先......
Raft是在1.4.1版的基于Kafka和Solo的ordering系统之后推出的共识插件。Raft为ordering服务带来了额外的功能,使生产系统就绪。在开始ordering服务之前,让我们首先了解Raft的基本知识。

共识机制的基础知识

共识算法允许一组计算机作为一个连贯的组工作,这些组可以在某些成员的故障中幸存下来。现在失败主要有两种:拜占庭式和非拜占庭式。

拜占庭容错:比特币是第一个通过引入工作量证明来解决拜占庭式错误的去中心化系统。在拜占庭系统中,通常不会崩溃或崩溃,而是该系统变得恶意并且可以操纵另一个系统并影响决策过程。 例如工作证明,权益证明,PBFT,RBFT。

如果任何分布式系统被设计来处理BFT,它几乎可以容忍任何类型的故障。

非拜占庭式容错:Raft属于这一类,通常将故障计为系统崩溃,网络故障,网络延迟,传输过程中的数据包丢失等,例如Kafka,Paxos,Zookeeper。

所以现在的问题是,为什么不在最安全的情况下使用基于BFT的共识机制呢?

因此,要回答这个问题,BFT需要3n + 1节点来管理本质上非常大的n故障。例如要处理BFT中的100个恶意节点,您至少需要301(3 * 100 + 1)个节点。这就是复杂性出现的地方。Raft尝试仅使用2n + 1(2 * 100 + 1)节点解决容错问题,但这仍然具有成本效益。因此,某些分布式系统仍然比其他替代方案更喜欢Raft。BFT最适用于分散公共网络,其中节点变得恶意的可能性更高。例如比特币,以太坊。在专用网络的情况下,该节点已经受到数字证书的保护,因此Raft在这种分布式系统上可以很好地工作。例如Quorum,Hyperedger Fabric。

什么是raft?

RAFT是一种分布式的容错一致性算法,它保证了系统在发生故障时能够做出决策并处理客户的请求。用技术术语来说,Raft是用于管理复制日志的共识算法。复制日志是复制状态机的一部分。

复制状态机(RSM):

RSM是构建分布式系统的基本体系结构。 它由服务器日志(仅附加日志由命令组成),共识模块(在我们的例子中是Raft)和状态机-SM(接受某些输入并产生某些输出的任何程序,都有自己的状态)组成。

RSM的工作流程:

1.客户端向Leader节点发送包含命令的请求。
2.Leader节点将新请求附加到其日志并将此请求发送到所有follower节点。Follower节点将把这个请求添加到他们的日志中并发送一条确认消息。
3.一旦大多数节点发送了一条确认消息,Leader就会将其日志提交到其状态机,从而产生一些输出。一旦Leader提交日志,Follower也将提交日志到他们的SM。
4.Leader会将回复发送给客户。

那么Raft在RSM中的作用是什么呢?

通过这种方式,RAFT确保Follower的日志与Leader的日志(复制的日志)相同,即使发生故障,整个分布式系统也可以充当单个实体。

客户在发送请求之前是否需要知道谁是Leader?

否,客户端可以将请求发送到任何节点,如果该节点是Leader,则可以处理该请求,如果它不是Leader,则它将将此请求转发到Leader节点。

RAFT的基本功能:

服务器状态:根据raft算法,一个节点只能处于三种状态

Follower(F):最初所有节点都将处于Follower状态。如果一个Follower没有收到任何信息,他就会成为候选人。Follower的日志可以被Leader覆盖。

Candidate(C):开始选举,如果获得多数票,就成为领导人。

Leader(L):处理客户机请求并确保所有follower拥有相同的日志副本。Leader不能覆盖其日志。

从C到F的转换:如果C发现已经有Leader当选或新任期开始,它将恢复为F状态。

从L到F的过渡:如果其他任何节点具有聘用条款,则当前的Leader将返回F状态。

Term:Term是任意长度,用连续整数编号。

每届任期都以选举开始,Candidate试图通过投票机制成为Leader,并在余下的任期内担任Leader。

如果出现分裂投票,而多数人无法决定,则会发生连任。为了避免分裂投票,每个服务器都有自己的选举超时时间(follower等待成为Candidate的时间)

Leader选举:

Raft使用心跳机制来触发Leader选举。服务器启动时,它们以follower的身份开始。只要服务器从Leader或候选者那里收到有效的RPC,它就保持follower状态。Leader定期向所有follower发送心跳信号(不携带日志条目的AppendEntries RPC),以保持其权威。如果follower在称为选举超时的一段时间内未收到任何通信,则它将假定没有可行的Leader,并开始选举以选择新的Leader。

要开始选举,follower会增加其当前任期并过渡到候选状态。 然后它为自己投票,并与集群中的其他每个服务器并行发出RequestVote RPC。

Candidate发送RequestVote到所有节点

一个Candidate继续处于这种状态,直到发生以下三件事之一:a)赢得选举,(b)另一台服务器确立自己的Leader地位,或者一段时间内没有赢家。

案例a:Candidate通过赢得其他节点的多数选票赢得选举并成为Leader。一个Candidate最多可以从另一个节点获得一票。

C5赢得选举并成为Leader

案例b:另一个节点的任期比候选节点的任期高,并宣布自己为Leader节点。

案例c:分裂投票,多个Candidate获得相同票数,但多数无法决定。

分裂投票-C1自投并接受来自F2和F3的投票,C3自投并接受来自F2和F3的投票

为了避免出现分裂投票的情况,请重新启动选举,并确保每个服务器都有随机的选举超时时间,以确保没有两个follower同时成为Candidate。

日志复制(Log Replication):

成功选举Leader后,便开始为客户的请求提供服务。每个客户端请求都包含一个由复制的状态机执行的命令。leader将命令作为一个新条目附加到其日志中,然后与其他每个服务器并行地发出AppendEntries rpc来复制该条目。当条目被安全复制(如下所述)后,leader将条目应用于其状态机,并将执行结果返回给客户端。

如果followers崩溃或运行缓慢,或者如果网络数据包丢失,则leader将无限期地重试AppendEntries rpc(即使在响应客户端之后),直到所有followers最终存储所有日志条目

日志一致性检查:发送AppendEntries RPC时,leader将在其日志中包括紧随新条目之前的条目的索引和术语。如果followers在其日志中找不到具有相同索引和术语的条目,则它拒绝新条目。一致性检查是一个归纳步骤:日志的初始空状态满足Log Matching属性,并且只要扩展日志,一致性检查都会保留Log Matching属性。 因此只要AppendEntries成功返回,leader就会知道followers的日志与它自己通过新条目记录的日志相同。

leader通过强迫followers的日志复制自己的日志来处理不一致问题。 这意味着followers日志中的冲突条目将被leader日志中的条目覆盖。

为了使followers的日志与自己的日志保持一致,leader必须找到两个日志一致的最新日志条目,在此之后删除关注者日志中的所有条目,并在此之后将关注者的所有leader条目发送给followers。所有这些操作都是响应AppendEntries RPC执行的一致性检查而发生的。

安全性:Raft确保日志覆盖过程是安全的。例如当leader提交多个日志条目时,followers可能不可用,然后它可以被选为leader并用新条目覆盖旧条目?

为了处理这种情况,选举限制已经到位。RequestVote RPC包含有关候选日志的信息,并且投票者会拒绝其自身的日志是否与候选日志更接近的最新信息。这样,过时的followers将永远不会被选为leader。

如果leader在提交日志X之前崩溃,该怎么办?

当leader崩溃时,将启动新的选举,新当选的leader已经具有旧的log X值。leader获取客户机提交log Y的请求,并为此leader向所有follower发送AppendEntries,一旦多数响应,leader将提交log Y。当logy即将提交时,所有以前的日志条目也将被提交,包括log X。

如果follower或Candidate崩溃了会怎么样?

Leader会继续发送AppendEntrries,直到无法恢复为止。如果它们在同一时间内没有恢复,则新Leader将继续执行一致性检查,并确保当节点启动时,它们具有最新的Log状态。

Raft在Hyperledger中的实现

基本概念 :

基于RAFT的ordering服务取代现有的Kafka OSN。每个节点都有自己的Raft状态机(RSM)来提交日志。客户端将使用广播RPC发送事务建议。Raft OSN将基于一致性形成一个区块,当peer发出DeiverRPC时,将块发送给peer。

Raft OSN的工作:

1:交易(即提案或配置更新)应由入口OSN自动路由到充当该通道当前Leader的OSN。(如果入口OSN是当前的Leader,则省略此步骤。)
2:leader检查验证此事务的配置序列号是否等于当前配置序列号。(如果不是这样,则重新验证事务,如果未通过验证检查,则拒绝该事务。)leader将传入的事务传递给blockcutter的Ordered方法;如果一个区块尚未形成,它将不执行任何操作。否则,将创建候选区块。
3:如果形成了一个区块,则leader OSN将其提交给局部Raft有限状态机。
4:FSM然后将尝试将区块复制到足够的OSN,以便可以提交该区块。
5:只有这样,才能将该区块写入接收副本的本地分类帐中。

每个通道的Raft:

每个通道将在Raft协议的单独实例上运行。换句话说:一个服务于N个频道的网络,意味着我们有N个Raft集群,每个集群都有自己的leader。当集群分布在不同的节点上时(正如我们希望的那样),这将进一步分散服务。然而即使这些集群分布在相同的节点上(正如我们预期的当前默认情况),这也使我们能够在每个通道上有不同的leader。

实现方式:

先决条件:

一旦所有二进制文件和docker镜像都安装了标签1.4.1。 我们将使用BYFN组件来演示Raft功能。BYFN具有5个ordering服务节点,2个org 4个peer和可选的CouchDB。 在configtx.yaml文件中给出了用于Raft的ordering服务(etcdraft-> librarby,已实现了raft算法)的配置,以创建创世块。

cd fabric-samples/first-network

./byfn.sh up-o etcdraft(使用默认go chaincode启动网络,raft共识,它将负责生成加密材料)

检查ordering服务:

docker logs -f ordrer3.example.com

启动Raft节点

由节点3发起的选举过程并成为第2任期的leader

验证Raft的容错能力:

关闭节点3:docker stop orderer3.example.com

第一个容错,节点3关闭下线,因此节点5被选为新的leader。

关闭节点5:docker stop order5.example.com

第二个容错,节点5下线,在可用节点1、2和4之外,节点2成为leader。

在2个容错之后验证系统:系统仍在工作,因为3个节点中的2:1大多数仍然有效。

查询a的分类帐状态:输出90

调用资金10的转移,从A到B。查询a的状态:90-10 = 80

第三容错:关闭更多节点:docker stop orderer2.example.com

调用事务将失败,因为在两个节点中,大多数无法确定。Error:服务不可用

具有5个节点的Raft最多可容忍2个故障。现在重新启动一个节点ordere3。

重启节点3:docker start ordere3.example.com

节点1成为节点1、2和3的领导者。

调用事务。结果:大部分2:1的Raft节点成功。

结论:Raft是成熟的共识算法,比Kafka易于大规模实现。 Fabric还计划在稍后阶段引入基于BFT的算法,以使系统更加安全可靠。

关键词: Raft共识  Raft  Hyperledger  
0/300