Hands-On Hyperledger Fabric——Byzantine-fault tolerant(BFT)过程详解

文章目录

  • 拜占庭问题描述
  • 分布式架构遭遇的问题
  • Practical Byzantine Fault Tolerance(PBFT)
    • PBFT过程详解

拜占庭问题描述

拜占庭将军问题是分布式计算中的一个经典问题。
拜占庭将军问题是Leslie Lamport(2013年的图灵奖得主)用来为描述分布式系统一致性问题(Distributed Consensus)在论文中抽象出来一个著名的例子。
这个例子大意是这样的:
拜占庭帝国想要进攻一个强大的敌人,为此派出了10支军队去包围这个敌人。这个敌人虽不比拜占庭帝国,但也足以抵御5支常规拜占庭军队的同时袭击。这10支军队在分开的包围状态下同时攻击。他们任一支军队单独进攻都毫无胜算,除非有至少6支军队(一半以上)同时袭击才能攻下敌国。他们分散在敌国的四周,依靠通信兵骑马相互通信来协商进攻意向及进攻时间。困扰这些将军的问题是,他们不确定他们中是否有叛徒,叛徒可能擅自变更进攻意向或者进攻时间。在这种状态下,拜占庭将军们才能保证有多于6支军队在同一时间一起发起进攻,从而赢取战斗?
拜占庭将军问题中并不去考虑通信兵是否会被截获或无法传达信息等问题,即消息传递的信道绝无问题。Lamport已经证明了在消息可能丢失的不可靠信道上试图通过消息传递的方式达到一致性是不可能的。所以,在研究拜占庭将军问题的时候,已经假定了信道是没有问题的。

单从上面的说明可能无法理解这个问题的复杂性,我们来简单分析一下:
先看在没有叛徒情况下,假如一个将军A提一个进攻提议(如:明日下午1点进攻,你愿意加入吗?)由通信兵通信分别告诉其他的将军,如果幸运中的幸运,他收到了其他6位将军以上的同意,发起进攻。如果不幸,其他的将军也在此时发出不同的进攻提议(如:明日下午2点、3点进攻,你愿意加入吗?),由于时间上的差异,不同的将军收到(并认可)的进攻提议可能是不一样的,这是可能出现A提议有3个支持者,B提议有4个支持者,C提议有2个支持者等等。
再加一点复杂性,在有叛徒情况下,一个叛徒会向不同的将军发出不同的进攻提议(通知A明日下午1点进攻, 通知B明日下午2点进攻等等),一个叛徒也会可能同意多个进攻提议(即同意下午1点进攻又同意下午2点进攻)。
叛徒发送前后不一致的进攻提议(“双花”),被称为“拜占庭错误”,而能够处理拜占庭错误的这种容错性称为「Byzantine fault tolerance」,简称为BFT。

分布式架构遭遇的问题

分布式架构会遭遇到以下问题:
1、异构环境的分布式架构首先可能遇到网络传输问题,比如数据丢失、延迟、重复、乱序。
2、欺骗攻击和重播攻击
3、操纵多个失效节点,延迟通讯,制造混乱。

具体到区块链世界,存在同样类似的问题:
区块链是一个分布式账本系统,参与者通过点对点网络连接,所有消息都通过广播的形式来 发送。系统中存在两种角色:普通节点和记账节点。普通节点使用系统来进行转账、交易等操作,并接受账本中的数据;记账节点负责向全网提供记账服务,并维护全局账本。 我们假设在此网络中,消息可能会丢失、损坏、延迟、重复发送,并且接受的顺序与发送的 顺序不一致。此外,节点的行为可以是任意的:可以随时加入、退出网络,可以丢弃消息、 伪造消息、停止工作等,还可能发生各种人为或非人为的故障。
其实这就是拜占庭将军问题。

Practical Byzantine Fault Tolerance(PBFT)

实用拜占庭容错是Hyperledger Fabric v0.6采用的方案

PBFT算法要求至少要4个参与者,其中1个被选举为军长,3个师长。军长接到总司令命令:你们向前行军500公里。军长就会给3个师长发命令向前行军500公里。3个师长收到消息后会执行命令,并汇报结果。A师长说我在首都以东500公里,B师长说我在首都以东500公里,C师长说我在首都以东250公里。军长总结3个师长的汇报,发现首都以东500公里占多数(2票>1票),所以就会忽略C师长的汇报结果,给总司令汇报说,好了,现在部队是在首都以东500公里了。这就是PBFT算法。

通过一个形象的比喻,其实这个理论的核心原则与Paxos相似,都是少数服从多数的决议。要完成少数服从多数的原则,就要满足 n ⩾ 3 f + 1 n\geqslant 3f+1 n3f+1,其中, n n n是系统中的总节点数, f f f是允许出现故障的节点数。换句话说,如果这个系统允许出现 f f f个故障,那么这个系统必须包括 n n n个节点,才能解决故障。

PBFT过程详解

上面的例子有几点描述的比较模糊,例如:职位阶级(总司令、军长、师长)是如何选择出来的?以及引申出来的新问题:如果军长叛变会怎么样?等等。现在重点描述一下PBFT的过程,解决上述问题。

类似于Paxos算法,首先介绍算法角色划分

  • client:请求的发起者(总司令)。
  • replica(副本):所有参与提供服务的节点,副本包括primary和backup(军长和师长)。
    • primary:承担起提供服务主要职责的节点(军长)。
    • backup:其他副本(师长)。
  • view:处于存在primary-bakup场景中的相对稳定的关系,叫视图。如果primary出现故障,这种相对稳定的视图关系就会转变(transit)。比如军长叛逃(出现故障,对外表现为不可见),那么某个师长就会转变成为军长。系统也就从视图a转变为视图b(a,b均为整数)。

所有的副本在一个被称为视图(View)的轮换过程(succession of configuration)中运作。在某个视图中,一个副本作为主节点(primary),其他的副本作为备份(backups)。视图是连续编号的整数。主节点由公式p = v mod |R|计算得到,这里v是视图编号,p是副本编号,|R|是副本集合的个数。当主节点失效的时候就需要启动视图更换(view change)过程。Viewstamped Replication算法和Paxos算法就是使用类似方法解决良性容错的。
PBFT对每个副本节点提出了两个限定条件:(1)所有节点必须是确定性的。也就是说,在给定状态和参数相同的情况下,操作执行的结果必须相同;(2)所有节点必须从相同的状态开始执行。在这两个限定条件下,即使失效的副本节点存在,PBFT算法对所有非失效副本节点的请求执行总顺序达成一致,从而保证安全性。

PBFT算法过程分为四个阶段

  1. request:client发起请求阶段(有些说法不包括这个阶段)。总司令给军长下命令。
  2. 预准备(pre-prepare):primary节点向所有backup节点发送预准备消息,其中包括当前视图编号(view number)请求(client request)以及请求摘要签名是否一致等。军长对各位师长说:现在是我的时代(视图),我是军长,你们都是师长,所有人都得听我的。现在公布总司令的命令(先说说总司令是谁,命令摘要)。
  3. 准备(prepare):包括primary节点在内的所有replica节点在收到准备消息之后,对消息的签名是否正确,视图编号是否一致,以及消息序号是否满足水线限制这三个条件进行验证,如果验证通过则把这个准备消息写入消息日志中。backup节点核对签名信息,比如其他师长听到总司令的名字,说对,总司令就是这个人没错,然后核对总司令曾经任命这家伙当军长,好吧,那就听他的吧。
  4. 确认(commit):每个副本接受确认消息的条件是:1)签名正确;2)消息的视图编号与节点的当前视图编号一致;3)消息的序号n满足水线条件,在h和H之间。一旦确认消息的接受条件满足了,则该副本节点将确认消息写入消息日志中。每个师长都经过上述核对,确认无误,就会接受命令进行执行。
  5. 回复(reply):结果反馈。

上述的消息请求使用了加密技术来防止欺骗攻击和重播攻击,以及检测被破坏的消息。消息包含了公钥签名(其实就是RSA算法)、消息验证编码(MAC)和无碰撞哈希函数生成的消息摘要(message digest)。使用m表示消息,mi表示由节点i签名的消息,D(m)表示消息m的摘要。按照惯例,只对消息的摘要签名,并且附在消息文本的后面。并且假设所有的节点都知道其他节点的公钥以进行签名验证。

根据上述过程,假设primary节点是个诚实节点,也就是主节点没有失效,但其他节点失效的情况
Hands-On Hyperledger Fabric——Byzantine-fault tolerant(BFT)过程详解_第1张图片
根据公式 n ⩾ 3 f + 1 n\geqslant 3f+1 n3f+1,提议通过。

主节点可能会是拜占庭的(主节点失效的情况):它可能会给不同的请求编上相同的视图序号,或者不去分配视图序号,或者让相邻的视图序号不连续。备份节点应当有职责来主动检查这些序号的合法性,并能通过timeout机制检测到主节点是否已经宕掉。当出现这些异常情况时,这些备份节点就会触发视图更换view change协议来选举出新的主节点。

你可能感兴趣的:(Fabric)