共识 | 拜占庭容错的表明 PBFT

共识 | 拜占庭容错的表明 PBFT

本文是共识系列文章的第一篇。在共识系列文章中,我将会向你们介绍常见的共识算法。在文章开头,我会用必定篇幅介绍一致性问题的基础知识。一致性问题是分布式系统中最基础也是最重要的问题,而共识算法就是用来解决分布式系统一致性的。以后,我会介绍一个很是经典的拜占庭容错算法 PBFT。git

预备

一致性

一致性(Consistency),早期也叫(Agreement),是指在分布式系统领域中,对于多个服务节点,给定一系列操做,在约定协议的保障下,使得它们对处理结果达成“某种程度”的协同。分布式系统达成一致的过程应知足:算法

  • 可终止性(Termination):一致的结果在有限时间内能完成;安全

  • 约同性(Agreement):不一样节点最终完成决策的结果是相同的;网络

  • 合法性(Validity):决策的结果必须是某个节点提出的提案。并发

共识

要保障系统不一样程度的一致性,就须要共识算法来完成。共识算法解决的是分布式系统对某个提案(Proposal),全部诚实节点达成一致意见的过程。那么共识须要解决的问题能够作以下的抽象:异步

  • 如何提出一个待共识的提案?分布式

  • 如何让多个节点对该提案达成共识?ide

CFT & BFT

对于分布式系统来讲,若是节点间通讯十分顺畅,各个节点都能瞬间响应,那么只须要简单广播投票和应答就能够解决一致性问题。而后现实并非这样。节点每每会遇到网络中断、节点故障,甚至是被非法入侵伪造消息的问题。节点遇到的问题能够进行以下的分类:区块链

  • 节点出现故障但不会伪造信息的状况称为“非拜占庭错误”;优化

  • 节点会伪造信息恶意响应的状况称为“拜占庭错误”,伪造信息的节点称为拜占庭节点。

相对应的,共识算法也能够分为 CFT 和 BFT 两类:

  • CFT(Crash Fault Tolerance):只容忍节点故障,不容忍节点做恶;

  • BFT(Byzantine Fault Tolerance):容忍节点故障与做恶。

 

FLP 不可能原理

计算机科学家证实了:在网络可靠,但容许节点失效的最小化异步系统中,不存在一个能够解决一致性问题的肯定性共识算法。这彷佛意味着去设计一个共识算法是徒劳的,然而科学告诉你什么是不可能的;工程则告诉你,付出一些代价,能够把它变成可行。也就是说在付出多大的代价的状况下,可以达到共识。

两军问题

白军驻扎在沟渠里,蓝军和红军分别驻扎在沟渠两边。白军比蓝军和红军中任何一支军队都更为强大,可是蓝军和红军若能同时协力进攻则可以战胜白军。蓝军和红军不可以越过沟渠远程地沟通,只能派遣通讯兵穿过沟渠去通知对方协商进攻时间。可是通讯兵可能会迷路或者被敌军截获,消息被篡改。

 

根据 FLP 不可能原理,这个问题无通用解,然而这一问题在通讯领域又必须解决。基于成本可控的考虑,如今使用 TCP 协议的三次握手来(不完全的)解决这一问题。

拜占庭将军问题

一组拜占庭将军分别各率领一支军队共同围困一座城市。为了简化问题,将各支军队的行动策略限定为进攻或撤离两种。由于部分军队进攻部分军队撤离可能会形成灾难性后果,所以各位将军必须经过投票来达成一致策略,即全部军队一块儿进攻或全部军队一块儿撤离。由于各位将军分处城市不一样方向,他们只能经过信使互相联系。在投票过程当中每位将军都将本身投票给进攻仍是撤退的信息经过信使分别通知其余全部将军,这样一来每位将军根据本身的投票和其余全部将军送来的信息就能够知道共同的投票结果而决定行动策略。

上述的故事映射到分布式系统里,将军便成了共识节点,叛徒就是拜占庭节点。与两军问题不一样的是,拜占庭将军问题中并不去考虑通讯兵是否会被截获或没法传达信息等问题,也就是说在假定信道没有问题的状况下去讨论一致性与容错性。

有了这些预备知识能够更好的理解共识算法。下面咱们进入今天的正题——PBFT。

PBFT 共识算法

PBFT 是 Practical Byzantine Fault Tolerance 的缩写,意为实用拜占庭容错算法。该算法首次将拜占庭容错算法复杂度从指数级下降到了多项式级,其能够在恶意节点不高于总数 1/3 的状况下同时保证安全性(Safety)和活性(Liveness)。咱们假设全部节点的总数为 R ,拜占庭节点数量为 f,下面给出安全性证实:

设想 f 个叛变者和 k 个忠诚者,叛变者故意使坏,能够给出错误的结果,也能够不响应。某个时候 F 个叛变者都不响应,则 k 个忠诚者取多数既能获得正确结果。当 f 个叛变者都给出一个恶意的提案,而且 k 个忠诚者中有 f 个离线时,剩下的 k - f 个忠诚者此时没法分别是否混入了叛变者,仍然要确保取多数能获得正确结果,所以,k - f > f,即 k > 2f 或 R - f > 2f,因此系统总体规模 R 要大于 3f。因此为了能确保达成共识的拜占庭系统节点数至少为 4,此时最多容许出现 1 个拜占庭节点。

PBFT 是一种基于状态机副本复制的算法,每一个状态机的副本都保存了服务的状态,同时也实现了服务的操做。PBFT 中全部的副本都在视图(View)的轮换过程当中运做,当主节点掉线的时候就启动视图更换过程保证算法的持续运行。

从上面的流程图能够看出,PBFT 算法的流程以下:

  1. 客户端向主节点发送请求;

  2. 主节点向其余副本广播请求;

  3. 全部副本执行请求后,将结果返回给客户端;

  4. 客户端须要等待 2f+1 个不一样副本返回相同的结果,做为最终结果。

这里面暗含着的是全部节点都是肯定性的和全部节点都从相同的状态开始执行这两个条件。

首先客户端发送了一个请求到主节点,以后经典的三阶段协议(three-phase protocol)就拉开了序幕。

预准备阶段

首先,主节点向全部副本节点发送预准备消息。这里面包含有消息序号,视图编号和消息的摘要。须要注意的是预准备消息是不包含请求的,这样作有两个好处,一是压缩消息大小提高传播效率,二是将请求排序与请求传输解耦。

接着副本节点会去验证消息的签名是否正确,视图编号是否一致和消息序号是否知足水线要求。这里就要引出 PBFT 中的水线机制(watermark)。对于消息的序号 n,要求其在水线 h 和 H 之间。水线存在的意义在于防止一个失效节点使用一个很大的序号消耗序号空间。

准备阶段

若是副本节点接受预准备消息,就进入了准备阶段。在准备阶段,每个节点都向其余节点发送包含本身 ID 的准备消息,同时也接收其余节点的准备消息。对于收到准备消息一样进行合法性检查。验证经过则把这个准备消息写入本身的消息日志中。一个节点集齐至少 2f+1 个验证过的消息才进入准备状态。

提交阶段

在提交阶段,每一个节点广播 commit 消息告诉其余节点本身已经进入准备状态。若是集齐至少 2f+1 的 commit 消息则说明提案经过。

在通过了三阶段协议以后,每一个副本节点都想客户端发送回复,副本节点会把时间戳比已回复时间戳更小的请求丢弃,以保证请求只会被执行一次。

总结

PBFT 共识算法在 1999 年的时候由 Castro 和 Liskov 正式提出,它在设计时考虑的共识对象是一些相对不大的消息。为了对消息进行排序,PBFT 设计了水线机制,经过 checkpoint 机制移动水线,用以并发地处理多个消息的投票过程。同时, PBFT 只有当某个节点做恶或掉线才触发视图的切换,主节点的更换。这是由于视图的切换过程也是须要共识的,这一过程很是耗时,所以 PBFT 不能接受频繁的视图变动。再加上为了配合水位机制,视图切换的消息都相对普通消息要大得多。由于以上缘由,PBFT 的设计很是复杂,效率不高。

然而,随着技术的发展,区块链技术的诞生轻松的化解掉了 PBFT 在设计上的一些问题。 在区块链中,每个消息(区块)先后相继,用于并发处理的水位机制毫无用处,所以水线机制以及为此服务的 checkpoint 机制就没有存在的意义了。没有了水线机制和 checkpoint,阻碍视图切换的就只剩下视图切换的共识过程了,而这一点又被区块链自己做为共识帐本的特色给简化掉了。若是节点的切换经过链上的数据来达成共识,那么本来须要通过在线共识的过程又省掉了。

所以大量的区块链项目都使用了改进的 PBFT 用做共识算法,做为拜占庭容错的表明的 PBFT 也在不断地优化的过程当中焕发出了新的生机。

 

ref:

1.区块链技术指南 :https://legacy.gitbook.com/book/yeasy/blockchain_guide/details

2.Castro M, Liskov B. Practical Byzantine fault tolerance[C]//OSDI. 1999, 99: 173-186.

相关文章
相关标签/搜索