PBFT之三阶段提交

PBFT之三阶段提交

1 前言

  Raft保证当复制状态机数量为3f+1时, 最多能够容许f个状态机虚假。
  一个view中只有一个primary 其余为副本。
  视图更改说明primary崩溃或失败。算法

2 算法流程

  1. 客户端发送请求到primary调用服务操做
  2. primary广播请求到全部节点
  3. 节点执行请求并返回响应到客户端
  4. 客户端等待从不一样的节点发送的结果相同的f+1个响应。响应内容为操做的结果。

算法对节点的要求:安全

  1. 节点必须是肯定性的(给予一系列参数执行操做必须产生相同的结果)。
  2. 节点必须以相同的状态启动

2.1 客户端c

  客户端经过发送消息 <REQUEST,o,t,c>primary请求状态机执行操做o
  t:时间戳用于确保该操做只执行一次,而且全部的请求都按照时间戳前后排序。
  由节点发送到客户端的消息包括(当前视图号v,容许客户端去跟踪视图发现当前的primary).优化

  节点直接发送响应到客户端,响应内容包括<REPLY,v,t,c,i,r>.
v:当前视图号。
t:响应请求的时间戳。
i:节点ID
r:执行操做获得的结果。日志

  • 客户端等待由不一样的节点返回的具备相同的tr的响应消息。
  • 若是客户端没有接收到足够的响应,将广播请求到全部节点。若是请求已经被处理,节点只简单地从新发送响应。
  • 节点保留发送到每个客户端的最新的响应消息。
  • 不然,若是节点不是primary,将会重定向请求到primary,若是primary没有多播请求到集群,将会被怀疑是错误节点。若是有足够多的节点怀疑则会发生视图更新。

3 正常状况下三阶段提交

  每个节点的状态包括服务的状态。消息日志包括节点被接受的信息,以及节点当前的视图。
  当primary接受到客户端的请求m,将开始三个阶段的协议进行自动多播请求到节点。
  除非消息的数量超出协议中给定的最大消息数量不然primary当即开始该三阶段协议。若是消息超过最大消息数,将会将请求放置缓冲区。code

  三阶段分为pre-prepare,prepare,commitblog

  • pre-prepareprepare阶段用于对在同一视图中发送的请求彻底排序,即便提出请求排序的primary为虚假节点也是如此。
  • preparecommit阶段用于确保在视图之间对提交的请求进行彻底排序

3.1 PRE-PREPARE阶段

  在pre-prepare阶段,primary定义了一个序列号n,到请求消息中。多播一个pre-prepare消息并联合消息m到全部节点。并将该消息添加到日志中。该消息内容为 <<PRE-PREPARE,v,n,d>_s,m> (_s表明签名)这里的v代表被发送的消息处于的视图。m是客户端的请求消息。dm的摘要。
  为了保持消息较小。请求没有包括在pre-prepare消息中。这是很重要的由于pre-prepare消息用于做为该请求定义的序列号n在视图v中的证实。另外,它将协议与协议彻底分离,以将请求传输到节点;容许咱们为协议消息使用针对小消息优化的传输,对于大型请求针对大消息使用优化的传输。
  节点接收到提供的pre-prepare消息后:排序

  • 请求中的签名和pre-prepare消息是有效的,而且dm的摘要。
  • 视图v是有效的。
  • 在视图v中没有接收到其余的具备序列号n的包含不一样摘要的消息。
  • pre-prepare消息中的序列号在低的阈值h与高阈值H之间。

  最后一个条件用于阻止错误的primary为了耗尽序列号空间而选择一个很是大的值。it

  若是节点i接受了 <<PRE-PREPARE,v,n,d>_s,m> 消息。节点将会进入prepare阶段,并多播 <PREPARE,v,n,d,i>_s 消息到全部其余的节点,并将该消息添加到它的日志中。不然将什么也不作。集群

3.2 PREPARE阶段

  节点(包括primary)接收了prepare消息:变量

  • 签名是有效的
  • 视图号与节点当前视图相同
  • 序列号在hH之间

  并添加他们到本身的日志中。

  只有当节点i已将如下消息添加到它的日志:

  • 请求m
  • 在视图v中具备序列号n且是请求mpre-prepare消息(来自不一样节点2f个)

  而且节点经过检查prepare消息与pre-prepare消息具备相同的视图,序列号和签名,才认为prepared (m,v,n,i) 消息为有效的。

  算法的pre-prepareprepare阶段保证诚实节点赞成视图中请求的总顺序。更准确的,确保如下的变量:

  • 对于任意的诚实节点j(包括i=j),若是prepared (m,v,n,i) 消息是有效的,那么prepared (m’,v,n,j) 消息是无效的。而且任何D(m') 不等于D(m).
  • 由于prepared (m,v,n,i) 消息和 R=3f+1代表至少有f+1个诚实节点在视图v中发送了序列号为npre-prepare消息或者是prepare消息。
  • 所以,对于prepared (m’,v,n,j) 消息若是是有效的,那么须要至少一个诚实节点必须发送两个冲突的prepare消息(或者是视图为vprimary发送pre-prepare消息),两个prepare消息具备相同的视图和序列号可是具备不一样的摘要信息。可是这是不可能的由于节点不是虚假节点。
  • 最后,关于消息摘要强度的假设可确保m不等于 m' 而且 D(m) 等于 D(m') 是不可能的。

3.3 COMMIT阶段

  当prepared (m,v,n,i) 消息为有效的那么节点i多播 <COMMIT,v,n,D(m),i>_s 消息到其余节点.这个过程为commit阶段。节点接收commit消息并添加该信息到日志中。

  • 签名是有效的
  • 消息中的视图号等于节点当前视图号
  • 序列号在hH之间

  若是而且只有当对于全部在f+1诚实节点中的节点iprepared (m,v,n,i) 消息都是有效的,那么committed (m,v,n,i) 消息则是有效的。
  若是而且只有当节点i从不一样的节点接收到2f+1commit消息(可能包括本身),而且与请求mpre-prepare消息匹配(具备相同的视图,序列号和摘要)。则committed-local (m,v,n,i) 消息是有效的。

commit阶段确保如下变量:

  • 若是对于一些诚实节点icommitted-local (m,v,n,i) 消息是有效的。那么committed(m,v,n) 消息是有效的。
  • 诚实节点赞成本地提交的请求的序列号,即便它们在每一个节点上以不一样的视图提交,进一步,在诚实节点上本地提交的任何请求最终都将在1个或多个诚实节点上提交。

  每个节点i在当committed-local(m,v,n,i) 消息是有效的,而且i的状态反应了在全部请求中该请求的序列号是最小的状况下将会执行该操做。确保了全部诚实节点能够以相同的顺序执行请求,保证了安全性。在执行完请求操做后,节点将返回一个响应到客户端。
  当请求的时间戳小于最后一次回复的时间戳时节点抛弃该请求。保证只执行一次。

  不依赖消息顺序交付。所以可能节点乱序提交请求。这是无所谓的,由于节点保持了pre-prepare,prepare,和commit消息日志一直到该请求被执行。

图展现了该算法的以一种正常的例子(没有primary虚假)的操做。节点0为primary,节点3为虚假节点。C为客户端.
图

相关文章
相关标签/搜索