PBFT算法

1.前提假设

1.1系统同步模型

区块链是一个典型的分布式系统,而分布式系统中如果要研究共识的话,就需要明确系统同步模型。

同步模型分为:

synchrony:节点所发出的消息,在一个确定的时间内,肯定会到达目标节点;

asynchrony:节点所发出的消息,不一定会到达目标节点;

partial synchrony:节点所发出的消息,虽然会有一定延迟,但消息一定会送达

synchrony是最理想的情况,若分布式系统为一个同步系统,共识算法的设计可以简化不少。在同步系统中节点的问题认定就是:超时没收到消息。asynchorny是更贴近现实的模型,但根据FLP impossible原理,但在asynchrony假定下,共识算法不可能同时满足safety和liveness。但我们为了设计符合实际应用场景的共识算法,目前的BFT类共识算法大多是基于partial synchrony假定,在PBFT原论文中称之为:weak synchrony。

即PBFT假设系统是异步的,网络中消息会出现延迟,但不会被无限的延迟。

1.1.1safety 和 liveness

safety:坏的事情永远不会发生,也就是共识机制不会产生错误的结果,比如一部分节点返回yes,另一部分返回no,在区块链的实际情况下,指的就是不会产生区块链分叉。

liveness:好的事情一定会发生,也就是系统持续有响应,在区块链的实际情况下,指的是共识机制持续正常运行,不会卡住,假如一个区块链系统的共识机制卡在了某个位置,那么新的交易是无法进行回应的,也就是不满足liveness。

1.2模型容错类型

PBFT算法假定错误可以是拜占庭类型的,也就是可以容忍任意类型错误,比如节点作恶、说谎等。这跟crash-down类型的错误不一样,raft、paxos这类共识算法只允许crash-down的类型错误。节点智能crash但不能产生假消息

1.2.1引入参数

PBFT容忍无效或者恶意节点数:f

系统中总节点数为:n

对于不同的错误类型,保证协议正常工作的总节点数如下表

错误类型总节点数n
Byzantine fault3f+1
crash-down fault2f+1

1.2.2防止拜占庭类错误总节点的数目的推算

①.假设系统中可能存在f个拜占庭结点,系统中有n个节点并且需要根据节点发送过来额消息进行判断。

②.为了使共识机制正常运作,在收到n-f个消息的时候,就应该对消息进行处理,因为可能有f个节点根本不发送消息。

③.我们根据收到的n-f个消息进行判断,判断的原则为至少有f+1个节点相同结果,即n-f>f。

④.在收到的n-f个消息中,无法确定其中有无错误节点过来的消息,其中也可能存在f个假消息。所以n-f-f>f。

1.3系统建模

由一组节点构成状态机复制系统,一个节点作为主节点(primary),其他节点作为备份节点(back-ups)。轮到某个节点作为主节点时,这称为系统的一个view(视图)。当节点出了问题,就需要进行view的更新,切换到下一个节点担任主节点。主节点更替不需要选举的过程,而是采用round-robin方式。

当系统的主节点接收到client(客户)发送来的请求,并产生pre-prepare消息,进入共识流程。

我们需要系统满足以下条件:

1.deterministic(确定性):在一个给定状态上的操作,产生一样的执行结果。

2.起点一致性:保证每个节点都有相同的起始状态

要保证non-fault节点对于执行请求的全局顺序达成一致。

2.共识机制流程

正常状态下的共识机制如下图所示。

 共识机制发挥作用的三个阶段(pre-prepare、prepare、commit)

其中pre-prepare阶段和prepare阶段确保了在同一个view下,正常节点对于消息m达成了全局一致的的顺序,使用order<v,m,n>来表示,在view = v下,正常节点都会对消息m,确认一个序号n。接下来的commit过程,配合上viewchange的设计(主节点可能会发生故障),实现了view的切换,也保证了对于m的的全局一致顺序,即order<v+1,m,n>,视图切换到v+1,依然会对消息m,确认序号n。

以下会将分别介绍五个阶段

2.1 request

客户端c向primary节点发送请求。消息格式为<REQUST,o,t,c>。o为请求的具体操作,t为请求时客户端追加的时间戳,c为客户端标识。REQUST:包含消息内容m,消息摘要d(m)。客户端对于请求进行签名

2.2 pre-prepare

①primary节点收到客户端的请求,进行校验客户端请求消息签名,非法请求则予以丢弃。正常则进入

②primary节点收到请求m,将请求m广播给其他节点,并给请求m分配一个序号n,并广播给其他节点。广播后消息会存在本地的lo中。

pre-prepare阶段的消息格式<<PRE-PREPARE,v,n,d>p,m>>,其中v表示当前view的编号,n为表示给m分配的序号,d为客户端消息摘要,m为消息内容。<PRE-PREPARE, v, n, d>为主节点签名。

③当back-up节点i节点收到主节点发来的pre-prepare消息时,会做以下几项验证操作:

        1.验证主节点发来的消息签名。

        2.当前副本节点没有收到了一条在同一v下并且编号也是n,但是签名不同的PRE-PREPARE信息。

        3.收到的消息序号n,在当前接收窗口内<h,H>。

        4.d与m的摘要是否一致。

若以上全部通过,则接受该消息,之后进入prepare阶段。该节点会广播(向所有节点包括primary节点广播)prepare消息。之后将消息存入自己的log中。

2.3 prepare

节点收到prepare消息后,会验证签名并检查是否为当前view的消息,同时检查消息序号n是否在当前的接收窗口内,验证通过则接受该消息,保存到自己的log中。

当节点满足以下3点时表明节点达成了prepared状态,记为prepared(m,v,n,i)

        1.在log中存在消息m

        2.在log中存在m的pre-prepare消息,pre-prepare(m,v,n)

        3.在log中存在2f个来自其他节点的prepare消息,prepare(m,v,n,i)

至此,可以确保view在不发生切换的情况下,对于消息m有全局一致的顺序。此外记录pre-prepare和prepare消息到log中,用于View Change过程中恢复未完成的请求操作。

也就是说在view不变的情况下:

        1.一个正常节点i,不能对两个及两个以上的不同消息,达成相同序号n的prepared状态。也就是不能同时存在prepared(m,v,n,i)和prepared(m',v,n,i)

        2.两个正常节点i、j,必须对相同的消息m达成相同序号n的prepared状态。

prepared状态十分重要,其涉及到view转换时,为了保证view切换前后的safety特性,需要将上一轮的view的信息传递到新的view。在pbft中就是将prepared状态信息传递到新的view。即新的view中需要在上一轮view的prepared信息基础之上,继续进行共识。

达成prepared状态后,节点会广播commit消息<COMMIT,v,n,d,i>i.

2.4 commit

当节点接收commit消息后,会进行一下几步验证:

        1.验证其他节点发来的消息签名。

        2.当前副本节点没有收到了一条在同一v下并且编号也是n,但是签名不同的commit信息。

        3.收到的消息序号n,在当前接收窗口内<h,H>。

        4.d与m的摘要是否一致。

当节点i满足:

达成了prepared(m,v,n,i)状态,并且收到了2f+1个commit(v,n,d,i)消息,则该节点达成了commit-local(m,v,n,i)状态。

达成commit-local状态之后,节点对于消息m就有了一个全局一致的顺序,可以执行reply to客户端了。

其中commit-local状态说明有2f+1个节点达成了prepared状态。其中需要记录其他节点发来的commit消息到log中。

2.5 relpy

节点达到commit-local后运行客户端的请求操作o,并返回<REPLY, v, t, c, i, r>给客户端,r:是请求操作结果,客户端如果收到f+1个相同的REPLY消息,说明客户端发起的请求已经达成全网共识,否则客户端需要判断是否重新发送请求给主节点。

3.垃圾回收

在以上算法流程中,为了确保在view change的过程中,能够恢复先前的请求,每一个副本节点都记录一些消息到本地的log中,当执行请求后back-up节点需要把之前该请求的消息清楚掉。最简单的做法是在reply消息后,再执行一次当前状态的共识同步,但这样会消耗很多资源,因此可以在执行完多条请求K条,后执行一次状态同步。这个状态同步消息就是checkpoint消息。

back-up节点i发送<CheckPoint,n,d,i>给其他节点,n是当前节点所保留的最后一个视图的请求编号,d是当前状态的一个摘要,该checkpoint消息记录到log中。如果back-up节点i收到了2f+1个验证过的checkpoint消息,则清楚先前日志中的消息,并以n作为当前的stable checkpoint。

实际上当副本节点i向其他节点发出checkpoint消息后,其他节点还没有完成K条请求,所以并不立即对节点i的请求作出响应,它还会按自己的节奏向前行进,但此时发出的checkpoint并未形成stable,为了防止节点i的处理请求过快,设置一个上文提到的高低水位区间[h,H]来解决这个问题。低水位h等于上一个stable checkpoint的编号,高水位H=h+L,L为我们指定的数值,等于checkpoint周期处理请求数K的整数倍,比如L=2K。当节点i处理请求超过H时,就会停止脚步,等待stable checkpoint发生变化,再继续前进。

以上机制类似于计算机网络中的滑动窗口机制。

4.视图切换(view change)

若primary节点作恶,它可能会给不同的请求编上相同的序号,活不分配序号,或让相邻序号不连续,back-up节点应当有义务来主动核实这些序号的合法性。若primary节点离线或者作恶,客户端设置超时机制,若超时,客会向所有back-up节点广播请求消息。back-up节点检测出primary节点作恶或离线,发起view change协议。

back-up节点向其他节点广播<VIEW-CHANGE,v+1,n,C,P,i>消息,

        n:为最新的stable checkpoint的编号

        C:对应于n的check-point 2f+1个CHECKPOINT消息集合

        P: 一个P_m组成的集合,m表示消息,m的序号是大于n的,P_m表示序号为m的达成prepared状态的消息集合。P_m内容包含关于m的1个pre-prepare消息和2f条prepare消息集合。

        i:节点id

当主节点p = v+1 mod |R| 收到2f个有效的VIEW-CHANGE消息后,向其他节点广播<NEW-VIEW,v+1,V,O>消息,V为有效的VIEW-CHANGE消息集合。O是主节点重新发起的未经完成的PRE-PERPARE消息集合。PER-PREARE消息集合的选取规则:

1.选取V中最小的stable checkpoint编号min-s,选取V中prepare消息的最大编号max-s。

2.在min-s和max-s之间,如果存在P消息集合,则创建<<PRE-PREPARE,v+1,n,d>,m>消息。否则创建一个空的PRE-PREPARE消息,即:<<PRE-PREPARE,v+1,n,d(null)>,m(null)>,m(null)为空消息,d(null)空消息摘要。

back-up节点收到primary节点的NEW-VIEW消息,验证有效性,若通过,则进入view = v+1,并开始O中PRE-PREPARE消息处理流程。

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
​什么是共识算法背景分布式系统集群设计中面临着一个不可回避的问题,一致性问题对于系统中的多个服务节点,给定一系列操作,如何试图使全局对局部处理结果达成某种程度的一致?这个一致性问题大致有如下的场景:节点之间通讯不可靠的,延迟和阻塞节点的处理可能是错误的,甚至节点自身随时可能宕机节点作恶举例说明,就比如有两家电影院同时售卖总量一定的电影票,在这样的场景下,要如何设计方式来保证两家电影院协调同步不出现超卖或者错卖的问题呢?共识算法,就是解决对某一提案(目标,投票等各种协作工作),大家达成一致意见的过程比如上述的买票问题,就可以有如下的设计:1.每次卖票打电话给其他电影院,确认当前票数2.协商售卖时间,比如一三五A卖,二四六B卖3.成立个第三方存票机构,它统一发票通过以上的设计,可以看出一个很重要的解决一致性算法的解决思路,即:将可能引发不一致的并行操作进行串行化,就是现在计算机系统里处理分布式一致性问题基础思路和唯一秘诀 著名的共识设计理论FLP 不可能性原理  共识算法的理论下限提出该定理的论文是由 Fischer, Lynch 和 Patterson 三位作者于 1985 年发表,该论文后来获得了 Dijkstra(就是发明最短路径算法的那位)奖。FLP 原理认为对于允许节点失效情况下,纯粹异步系统无法确保一致性在有限时间内完成。三人三房间投票例子三个人在不同房间,进行投票(投票结果是 0 或者 1)。三个人彼此可以通过电话进行沟通,但经常会有人时不时地睡着。比如某个时候,A 投票 0,B 投票 1,C 收到了两人的投票,然后 C 睡着了。A 和 B 则永远无法在有限时间内获知最终的结果。如果可以重新投票,则类似情形每次在取得结果前发生带入到计算机领域就是说,即便在网络通信可靠情况下,一个可扩展的分布式系统的共识问题的下限是无解。即可靠性的下限是0%CAP  分布式系统领域的重要原理CAP 原理最早由 Eric Brewer 在 2000 年,ACM 组织的一个研讨会上提出猜想,后来 Lynch 等人进行了证明• C(一致性):所有的节点上的数据时刻保持同步,即数据一致• A(可用性):每个请求都能在一定时间内接受到一个响应,即低延迟• P(分区容错):当系统发生分区时仍然可以运行的定理:任何分布式系统只可同时满足二点,没法三者兼顾。即数据一致,响应及时,可分区执行不可能同时满足。举个例子:一个分布式网路上,某一个节点有一组依赖数据A,当网络无延迟,无阻塞时,依赖于X的操作可正常进行。但网络无延迟阻塞在现实世界中是没法100%保证的,那么当网络异常时,必然会产生分布式系统的分区和孤岛,那当一个执行操作在A分区之外时,如果要保证P,即当系统发生分区时仍可运行,就需要在分布式系统中多个节点有X的备份数据,以应对分区情况。则这时候就需要在C,A之间做出选择。假如选择C,即要保证数据在分布式网络中的一致性,那么就需要在X每次改动时,需要将全网节点的X数据同步刷新成最新的状态,那么在等待数据刷新完成之前,分布式系统是不可响应X的依赖操作的,即A的功能缺失假如选择A,即要突出低延迟的实时响应。那么在响应的时候,可能全节点的X数据并没有同步到最新的状态,则会导致C的缺失。上面看上去有些绕,那么你只要记住这句话,CAP原理在分布式网络系统的应用讨论,其实就是讨论在允许网络发生故障的系统中,该选择一致性还是可靠性?如果系统重视一致性,那么可以基于ACID原则做系统设计即 Atomicity(原子性)、Consistency(一致性)、Isolation(隔离性)、Durability(持久性)。ACID 原则描述了对分布式数据库的一致性需求,同时付出了可用性的代价。• Atomicity:每次操作是原子的,要么成功,要么不执行;• Consistency:数据库的状态是一致的,无中间状态;• Isolation:各种操作彼此互相不影响;• Durability:状态的改变是持久的,不会失效相应的有一个BASE原则,(Basic Availiability,Soft state,Eventually Consistency)则强调了可用性。 经典的共识算法设计业内,针对节点异常的情况,会有两种分类1.故障的,不响应的节点,成为非拜占庭错误2.恶意响应的节点,称为非拜占庭错误Paxos 最早的共识算法  非拜占庭算法的代表Paxos有三种角色:• proposer:提出一个提案,等待大家批准为结案。客户端担任该角色;• acceptor:负责对提案进行投票。往往是服务端担任该角色;• learner:被告知结案结果,并与之统一,不参与投票过程。即普通节点系统运行由proposer驱动,当合法提案在一定时间内收到1/2以上投票后达成共识。因此,可得出无法达成共识的条件:1.proposer故障2.二分之一以上acceptor故障拜占庭问题与BFT(Byzantine Fault Tolerant) 算法Leslie Lamport 1982 年提出用来解释一致性问题的一个虚构模型。拜占庭是古代东罗马帝国的首都,由于地域宽广,守卫边境的多个将军(系统中的多个节点)需要通过信使来传递消息,达成某些一致的决定。但由于将军中可能存在叛徒(系统中节点出错),这些叛徒将努力向不同的将军发送不同的消息,试图会干扰一致性的达成。拜占庭问题即为在此情况下,如何让忠诚的将军们能达成行动的一致。对于拜占庭问题来说,假如将军总数为 N,叛变将军数为 F,则当N>=3F+1 时,问题才有解,即叛变的将军不超过1/3时,存在有效的算法,如BFT,不论叛变者如何折腾,忠诚的将军们总能达成一致的结果。这是一个数学论证的结论,有兴趣的同学可以自行推导。PBFT  一种高效拜占庭容错共识算法PBFT是Practical Byzantine Fault Tolerance的缩写,意为实用拜占庭容错算法。该算法是Miguel Castro 和Barbara Liskov(2008年图灵奖得主)在1999年提出来的,解决了原始拜占庭容错算法效率不高的问题。他的核心思想是:对于每一个收到命令的将军,都要去询问其他人,他们收到的命令是什么。如上图,假设命令由A将军分发,假如A是作恶异常,分发给B,C,D的操作分别是1,2,3.意图扰乱共识。拜占庭容错算法上设计实现是,当B,C,D收到命令后,相互之间也会沟通从A收到的命令是否一致,从而达到识破干扰的目的。其容错的极限值就是N>=3F+1。PBFT 在区块链上的实现区块链的节点分为记账节点和普通节点两个角色记账节点负责向全网提供记账服务,并维护全局账本,每过一段时间从记账节点中选一个议长,进行命令的分发,其他记账节点则作为议员进行验证将军就是记账节点,拥有全局账本,并验证交易的有效性,过互相传达验证结果,在f共识的一般流程如下:1.任一节点接收到发送者签名的交易数据请求后,向全网广播2.所有记账节点均独立监听全网的交易数据,并记录在内存3.议长在经过t后发送共识请求提案request4.议员在收到提案后,进行相关验证,发送响应response5.任意节点在限定时间内收到至少F+1个response后,共识达成,把交易记录入区块并发布给全网,如果超时,则更换视图和议长6.任意节点在收到完整区块后,把包含的交易从内存中删除开始下一个共识循环区块产生间隔t,    记账节点n,  可容错节点数f, 视图编号v,  区块高度h, 议长编号p,  议员编号i p=(h-v)%n  未来的发展POW算法建立了比特币帝国,具有划时代的意义。但其能耗和速度问题却是制约区块链普及的两大难以解决的问题。目前POS算法是一大趋势,以太坊的Casper,EOS的DPos等都是借鉴了上述前人的设计理念做的基于应用场景的优化改造,但万变不离其宗,我和大家一样,需要不断的学习和思考,没准,能有发明出自己的共识算法的一天呢。 

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值