在了解分布式原理之前,我们先思考一个场景,有一个10000人的社区,社区里面的居民都是权责均等。为了社区的可持续发展,每年都会有热心的居民提出一些需求,比如新增门禁系统,增加保安人数,修缮小区路灯,疏通下水道,增加停车位等等需求。
现在问题来了,因为社区的预算是有限的,每年能实施的需求数量只有10个,到底哪些需求能通过?大家可能会想到,那就召开一个10000人的表决大会,大家投票表决,票数最高的前10个需求通过。问题又来了,需求这么多,如果一个个投票,不知道要到什么时候。要召开一个10000人的表决大会,需要大家都到场,前期宣传,场地布置,工作人员,监督人员也是一笔不小的支出。需求通过以后,谁来监督需求的实施,又是一件很麻烦的事情。
有的读者想到,那就选10个社区居委会代表出来,让居委会代表来负责审议通过哪些需求和监督实施。这是一个不错的提议,但是问题又来了,如何保证这些居委会代表在审核需求和监督实施的时候能够公开公正,当然可以引入代表监督,换届选举等等机制,但是又会引入一些新的问题。
我们再假设如果这是一个流动性很强的社区,每天都会有人加入,也有人离开,社区的人数和通过需求的数量并不固定,另外随时都可能会有新的需求产生。问题又会进一步变得错综复杂。
我们再进一步思考,如果这是一个计算机网络,网络中是很多计算机,随时可能会有新的计算机加入,已经加入的计算机即也随时会有可能宕机,如何判定网络中的计算机谁能够新增提案,新增的提案又能够被其他计算机所接受。问题好像变得更复杂了。
我们在面对这样的问题的时候,其实是很难找到完美的解决方案,必须要做相应取舍。但是如何去取舍,如何保证取舍之后开发出来的系统没有安全漏洞,这样的系统它的理论边界又在哪里?
我们先要总结出对分布式计算机网络的要求,在这个要求的基础上归纳出分布式计算机网络的要素,再通过严谨的逻辑证明推导出分布式原理,这样我们就知道在一个分布式的计算机网络中哪些需求是可以实现的,哪些需求是不可能实现的,哪些需求是在牺牲一些条件后可以实现的。在这个基础上,我们才能构建出合理的方案,解决我们面临的问题。这些方案尽管在科学理论上并不完美,但是通过适当的取舍,在工程上是可以实现的,这就是我们学习分布式原理的价值。
现在开始我们的分布式原理学习之旅吧。
1.1 去中心化与分布式
1.1.1 什么是去中心化
去中心化是互联网发展过程中形成的社会关系形态和内容产生形态,是相对于“中心化”而言的新型网络内容生产过程。
去中心化,并不是不需要中心,而是由节点来自由选择中心、自由决定中心。简单地说,中心化的意思,是中心决定节点。节点必须依赖中心,节点离开了中心就无法生存。而在去中心化系统中,任何人都是一个节点,任何人也都可以成为一个中心。任何中心都不是永久的,而是阶段性的,任何中心对节点都不具有强制性。
中心化的服务往往依赖于中心,两个节点之间的通讯都需要经过中心中转,系统高效但是依赖中心。而去中心化的服务,不需要依赖特定的中心,节点两两之间即可通信,系统健壮但是整个系统同步效率低。
在实践中,中心化和去中心化并不绝对是谁优谁劣。在一些场景中,中心化有其优势,在另外一些场景中去中心化有更高的价值。更多实际情况是,一个复杂的系统既会有中心化的部分,又会有去中心化的部分。例如在现实世界中,数字货币交易所里面比特币的交易是去中心化的,但是账户登录注册部分又是中心化的。
1.1.2 分布式
分布式是一门计算机科学,分布式分为分布式计算和分布式存储两个范畴。
分布式计算是研究如何把一个需要非常巨大的计算能力才能解决的问题分成许多小的部分,然后把这些小的部分分配给许多计算机并行处理,最后把这些计算结果综合起来得到最终的结果。分布式计算可以提升系统的计算能力。
分布式存储是指将数据存储在多台独立的存储服务器上,其中既有将数据分块存储在不同的服务器上,也有将相同的数据存储在不同的服务器上。将数据分块存储在不同的服务器上,可以解决传统单台服务器的存储大小限制的问题,将相同的数据数据存储不同服务器可以避免在单台服务器出现故障,导致不可用,另外也可以做负载均衡和就近读写数据。分布式存储可以提升系统的可靠性、可用性和扩展性。
现在主流的大数据产品,都是通过分布式存储和分布式计算来共同实现。区块链本身是分布式账本数据库,同时区块链因为存储数据结构的特点,随着时间的推移,数据量只会不断增加。区块链现阶段更多是指分布式存储中的将相同的数据存储在不同的对等节点,在有的区块链系统中单个对等节点也会分块存储数据,有些区块链系统也会用到分布式计算。我们接下来讨论的主要是分布式系统中如何将同一份数据存储在不同的对等节点。
区块链是一种特殊的分布式系统,具体来讲分为三部分:
一、分布式信息传递:每个参与区块链系统的节点都可以传递信息,每一个参与的节点都可与相邻节点进行信息交互,根据信息的先后顺序来决定是否更新节点的数据,从而实现全网公开传递有价值的信息。
二、分布式记账:每个参与系统的节点只要根据共识机制,完成相应的设定,便能取得数据库的记账权,记录可以追溯查询,但是不可以篡改。
三、分布式存储:分布式记账时,记录新的信息会加上之前信息的加密值和时间戳,然后产生区块数据,网络广播出去后,就会在区块链中各个节点储存,每个节点可以选择储存完整的数据或者是部分数据。通过储存实时的更新,每个节点都可以拥有一份完整的本地数据。
区块链技术的数据共享是一个分布式的记账簿,交易记录具备多个副本,因此首先要解决分布式数据存储的问题。区块链存储的基本单元是区块,区块采用链式结构,即新增的区块都需要能够跟踪到前一个区块,可以一直追溯到创世块,区块的标识是区块的hash值,同时链式结构保留了业务产生的历史顺序,可以在新增交易的时候根据前面的记录做校验,保证了区块的内容不容易篡改。
这种数据递增的方式,我们在传统的数据库设计也会采用,例如日志表的形式,每次对数据的操作都采用新增一条记录的模式,保留全部的历史记录,但是没办法保证数据不被删除或篡改。区块链加入了hash、时间戳等技术,把不容易篡改这一点变成了一种底层技术机制,保证链条上的数据的正确性和完整性,因此非常的有价值。
1.2 分布式系统的一致性
我们先通过一个场景来了解什么是一致性问题,如果你要预定一张下周日从上海飞往洛杉矶的机票,指定好的航班。那你可以去机场,携程,京东,或者淘宝等渠道购买,但是同一个航班,总的机票只有那么几百张,这就要求各个出票渠道需要对该航班的机票做出一个实时一致性的要求。否则就可能发生机票超卖,一个位置被卖给多个乘客,这是不允许的。
数据一致性其实是数据库系统中的概念。我们可以简单的把一致性理解为正确性和完整性,那么数据一致性通常指关联数据之间的逻辑关系是否正确和完整。我们知道,在数据库系统中通常用事务(在计算机术语中是指访问并可能更新数据库中各种数据项的一个程序执行单元)来保证数据的一致性和完整性。而在分布式系统中,数据一致性往往指的是由于数据的复制,不同数据节点中的数据内容是否完整并且相同。如何保证数据在不同数据节点在时间和空间上的一致性,往往是分布式系统面临的最大挑战。
1.2.1 一致性的定义
一致性就是数据保持一致,在分布式系统中,可以理解为多个节点中数据的值是一致的。一致性又可以分为强一致性与弱一致性。
1.强一致性
强一致性可以理解为在更新操作完成之后,任何后续的访问将返回更新的值。同一时间点,用户在节点A中获取到key的值与在节点B中获取到同一个key的值应该都是一样的。用户的体验很好,但是对系统的性能影响很大。
2.弱一致性
弱一致性约束了系统在写入成功后,不承诺立即可以读到写入的值,也不承诺多久之后数据能够达到一致,但会尽可能地保证到某个时间级别(比如秒级别)后,数据能够达到一致状态,目前分布式系统中广泛实现的弱一致性主要是最终一致性。
3.最终一致性,是弱一致性的一种特例,之所以将最终一致性单独提出来,是因为它是弱一致性中非常经典的一种一致性模型,也是业界在大型分布式系统的数据一致性上使用非常多的模型。系统会保证在一定时间内(共识算法的实现时间),能够达到一个数据一致的状态。也可以简单的理解为在一段时间后,不同节点上的同一份数据总是在向趋同的方向变化,任意历史时刻的数据在节点间最终会达到一致状态。
对于最终一致性最好的例子就是DNS(域名系统),全球一共有13个(字母A到M)根DNS(根DNS只是具有13个IP地址,但机器数量不止13台)。当然不可能全球所有的域名解析都要直接访问这13个根DNS服务器,这样的话13个根DNS服务器肯定抗不住。这个时候就要依赖DNS多级缓存来实现。正是因为有了DNS多级缓存,所以修改DNS解析记录后没办法在全球所有DNS服务节点立刻生效,需要等待其他DNS服务器的缓存过期后,向根DNS服务器读取最新的记录,然后更新自身解析记录才能实现。这里就实现了域名解析的最终一致性。
1.2.2 面临的问题
在分布式系统引入复制机制后,不同的数据节点之间由于网络延时等原因很容易产生数据不一致的情况。复制机制的目的是为了保证数据的一致性。但是数据复制面临的主要难题也是如何保证多个副本之间的数据一致性。
假设有这样的场景,有两个用户,用户A和用户B同时去抢购春节同一天从上海开往北京的火车票。为了保证不出现火车票超卖的情况,火车站的票务系统需要在京东和携程之间同步关于剩余票数的数据,目前显示只有1张余票了。1张票当然只能卖给一个人。
如果为了保证系统性能,那么A和B在购票的时候应该都可以下单成功。两人在支付之后,系统在做数据复制时发现一张票被卖出了两次,这时就要让用户A和用户B两人其中后买的人手中的火车票作废掉。这时就要花费很大的成本来通知后买到这张票的人。
如果为了保证数据一致性,那么用户A和用户B下单请求都需要等待返回,其中必定有一个用户的下单请求会失败,下单失败的用户需要等待在系统间完成余票数据同步,余票的数据更新为0。这个时候下单失败的用户才知道没有票了。
因为并发的写请求需要在前一个写请求结束之后才能进行。分布式系统在数据一致性和性能两个方面很难做到同时满足。如何能既保证系统数据一致性,又保证系统的性能,是每一个分布式系统都需要重点考虑和权衡的。在做这些考虑和权衡的时候,基于CAP定理可以帮助我们做出决策。
1.3 CAP定理
CAP定理是加州大学伯克利分校(University of California, Berkeley)的计算机科学家埃里克·布鲁尔在2000年的分布式计算原则研讨会 (Symposium on Principles of Distributed
Computing(PODC))上提出的一个猜想。 在2002年,麻省理工学院(MIT)的赛斯·吉尔伯特和南希·林奇发表了布鲁尔猜想的证明, 使之成为一个定理。定理讨论了在两个互相矛盾的请求到达彼此连接不通的两个不同的分布式节点的时候的处理方案。从此,CAP理论正式在学术上成为了分布式计算领域的公认定理,并深深地影响了分布式计算的发展。
作为分布式系统理论的基础,CAP定理(CAP theorem)指出对于一个分布式计算系统来说,不可能同时满足以下三点:
一致性(Consistence):所有节点访问同一份最新的数据副本;
可用性(Availability):每次请求都能获取到非错的响应——但是不保证获取的数据为最新数据;
分区容错性(Partition tolerance):以实际效果而言,分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择。
图1 CAP理论示意图
根据定理,分布式系统只能满足三项中的两项而不可能满足全部三项。
由于分布式系统难免遭遇网络故障,分区容错性就是一个必须面对和解决的问题。通常在分布式系统设计时就需要在一致性和可用性两者间进行选择。当选择一致性时,如果得到的回复信息不是最新的,系统会返回错误或延时;当选择可用性时,系统通常会处理请求并尽可能返回最新版本的可用信息,但是由于分区容错性,返回数据可能不是最新的。当分布式系统正常运行的情况下,一致性和可用性是可以得到同时满足的。这就意味着在网络故障不存在的前提下,分布式架构设计无需权衡一致性和可用性。
基于传统ACID设计的数据库系统,例如关系型数据库,选择一致性优于可用性。而如NoSQL这种基于BASE理论的系统则把可用性作为优先考量。接下来我们介绍ACID和BASE。
1.4 ACID原则和BASE理论
1.4.1 ACID原则
事务(transaction)是恢复和并发控制的基本单位。事务应该具有4个属性:原子性、一致性、隔离性、持久性。这四个属性通常称为ACID特性。
原子性(atomicity):一个事务中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被恢复到事务开始前的状态,就像这个事务从来没有执行过一样。
一致性(consistency):在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。要注意的是ACID一致性不等同于CAP的一致性,CAP的一致性是指所有节点访问同一份最新的数据副本。ACID的一致性是指系统没有任何的约束被破坏,一直都是保持正确的状态。
隔离性(isolation):数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(Read committed)、可重复读(Repeatable read)和串行化(Serializable)。
持久性(durability):事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
ACID原则的理论比较精炼,我们可以通过一个例子来深入了解。
例如用户A转账给用户B1000元,实际上是2个步骤,用户A减少1000元,用户B增加1000元,要么这2个步骤都成功,要么这2个步骤都不成功。否则就会出现用户A减少了1000元,用户B没增加1000元,这1000元就消失了,这种情况是不可接受的。或者出现用户A没减少1000元,但是用户B增加了1000元,凭空多出1000元,这也是不可接受的。如果有一个步骤失败了,必须回滚到最初的状态,这里就体现了原子性。隔离性指的是用户A如果同时还要转账给用户C 1000元,转给用户C的这个事务不应该对转给用户B这个事务产生影响,必须排队串行处理。而一致性更多指的应用层面的约束,一致性是一个完整状态,原子性和隔离性都是为了实现一致性。持久性指的是用户A给用户B转账1000元完成以后,如果系统出现故障再恢复以后,这笔转账还是应该存在的。
ACID 原则描述了对分布式数据库的强一致性模型,如果要完全实现,根据CAP定理,必然付出可用性的代价。如果我们说CAP定理从理论上确定了实现分布式系统的上限,那么接下来的BASE理论就确定了实现分布式系统的所应该满足的基本条件。
1.4.2 BASE理论
eBay的架构师Dan Pritchett源于对大规模分布式系统的实践总结,在ACM上发表文章提出BASE理论,BASE理论是对CAP理论的延伸,核心思想是即使无法做到强一致性(Strong Consistency,CAP的一致性就是强一致性),但应用可以采用适合的方式达到最终一致性(Eventual Consitency)。
BASE是Basically Available(基本可用)、Soft state(软状态)和Eventually consistent(最终一致性)三个短语的缩写。BASE理论是CAP理论结合实际的产物。 BASE在英文中有碱的意思,这个正好和ACID的酸的意义相对。
BASE也恰好和ACID是相对的,BASE要求牺牲高一致性,获得可用性或可靠性。BASE理论是对CAP中一致性和可用性权衡的结果,其来源于对大规模互联网系统分布式实践的总结,是基于CAP定理逐步演化而来的。BASE理论的核心思想是:即使无法做到强一致性,但每个应用都可以根据自身业务特点,采用适当的方式来使系统达到最终一致性。
接下来看一下BASE中的三要素:
1、基本可用 :基本可用是指分布式系统在出现不可预知故障的时候,允许损失部分可用性----注意,这绝不等价于系统不可用。比如:(1)响应时间上的损失:正常情况下,一个电商网站商品详情页打开需要0.5秒,但由于部分节点出现故障,请求其他节点导致商品详情页的响应时间增加了1~2秒;(2)系统功能上的损失:正常情况下,在一个电商网站上进行购物的时候,消费者几乎能够顺利完成每一笔订单。但是在“双11”、“618”网购大促的时候,由于用户购物发生集中高并发,为了保证电商系统的基本可用,部分用户可能会被引导到一个系统繁忙,请稍后再试的页面。
2、软状态 :软状态指允许系统中的数据存在中间状态,并认为该中间状态的存在不会影响系统的整体可用性,即允许系统在不同节点的数据副本之间进行数据同步的过程存在延时。
3、最终一致性 :最终一致性强调的是所有的数据副本,在经过一段时间的同步之后,最终都能够达到一个一致的状态。因此,最终一致性的本质是需要系统保证最终数据能够达到一致,而不需要实时保证系统数据的强一致性。
BASE理论面向的是大型高可用可扩展的分布式系统,为了保证系统的稳定可靠对于可用性放宽了一定的要求。在开发和架构设计时,要根据业务场景和系统要求选择合适的一致性模型。对系统可用性和一致性要求高的用例如金融或银行系统,ACID数据库是最优选择。而一些高并发同时对扩展性要求高的系统如面向C端的互联网应用,则可以考虑融入BASE理论。
1.5 一致性算法
分布式系统中的节点通信存在两种模型:共享内存(Shared memory)和消息传递(Messages passing)。共享内存的应用场景有限,分布式系统的节点通信主要是指消息传递。基于消息传递通信模型的分布式系统,不可避免的会发生以下错误:进程可能会慢、被杀死或者重启,消息可能会延迟、丢失、重复。
这种情况下,就需要一致性算法来解决分布式系统可能出来的各种情况。Paxos 和 Raft 是目前分布式系统领域中两种非常著名的解决一致性问题的共识算法,两者都能解决分布式系统中的一致性问题,Paxos的实现与证明比较难以理解,Raft的实现比较简洁符合人们的思维习惯,Raft的出现就是为了解决 Paxos 难以理解和难以实现的问题。
但是Paxos在一致性算法领域具有开创性的地位。以至于Google Chubby 的作者Mike Burrows指出世界上只有一种一致性算法,那就是Paxos,所有其它一致性算法都是Paxos算法的不完整版。
1.5.1Paxos算法
1990年 Leslie Lamport 提出了 Paxos 算法,Paxos算法是一种基于消息传递且具有高度容错特性的一致性算法。Paxos 被广泛应用在 Chubby、ZooKeeper 这样的系统中,Leslie Lamport 因此获得了 2013 年度图灵奖。
Paxos是一种能够解决分布式一致性问题的协议,使用这个协议,分布式系统中的一组机器对一个成员提议的值来达成共识。它能够让分布式网络中的节点在出现错误或多个节点同时提交不同的值时仍然保持一致。为了描述 Paxos 算法,Lamport在发表于ACM的论文《The Part-Time Parliament》中虚拟了一个叫做 Paxos 的希腊城邦。这个城邦按照议会民主制的政治模式制定法律,议员的角色分为提案者(Proposers),接受者(Acceptors)和学习者Learners(允许身兼数职)。Proposers 提出提案,提案信息包括提案编号和提议的 内容(value);Acceptor 收到提案后可以接受(Accept)提案,若提案获得多数Acceptors 的接受,则称该提案被接受(chosen);Learners 只能“学习”被批准的提案。
一个提案的决议过程分为两个阶段,准备阶段(Prepare)和接受阶段(Accept)。
图2 Basic Paxos两阶段示意图
John Ouesterhoutand Diego Ongaro. Implementing Replicated Logs with Paxos.Stanford University
准备阶段:
Proposer选择一个提案编号n;
将Prepare(n)请求广播给所有的服务器;
Acceptor收到Prepare消息后,如果提案编号大于它已经回复的所有Prepare消息,则Acceptor将自己上次接受的提案回复给Proposer,并不再回复小于n的提案;
接受阶段:
当一个Proposer收到了多数Acceptors对Prepare的回复后,将Acceptor回复的AcceptedValue作为编号最高的提案的内容。
Proposer向回复Prepare请求的Acceptors发送Accept请求。
在不违背自己向其他Proposer承诺的前提下,Acceptor收到Accept请求后即接受这个请求。
如果一个Proposer发现已经有其他Proposers提出了编号更高的提案,则有必要中断这个过程而返回步骤1。
当Acceptors接受一个提案时,会将这个消息发送给所有Learner。由于假设没有拜占庭错误,Learners可以通过别的Learners获取已经通过的决议。因此Acceptors只需将接受的消息发送给指定的某一个Learner,其他Learners向它询问已经通过的决议。但是指定Learner失效将引起系统失效。因此Acceptors需要将Accept消息发送给Learners的一个子集,然后由这些Learners去通知其他所有Learners。这样可以确保系统的稳定性,但也导致了通信的复杂度。
由于消息传递过程中存在丢失的情况,可能发生一个提案被接受却没有任何Learner获得决议批准的消息。当Learners需要了解决议通过情况时,可以让一个Proposer重新进行一次提案。
上面我们讲到的是Basic Paxos,由于大多数的分布式集群都需要接受一系列的值,如果使用 Basic Paxos 来处理数据,就会导致非常明显的性能损失。Multi-Paxos 引入了Leader的角色,所有的请求都会转发给Leader,如果系统中的 Leader 是非常稳定的,那么我们往往不需要准备阶段的工作,这样就能够将节点的数量减少一半。
1.5.2 Raft算法
Raft 其实就是 Multi-Paxos 的一个变种。作为管理复制日志的共识算法,Raft 通过简化 Multi-Paxos 的模型,实现了一种更容易让人理解的共识算法,并且同时保证和Paxos同等的效率。为了更易于理解,Raft对共识的几个关键特性如Leader选举、日志复制和安全进行了优化。Raft的3个显著特性如下:
强Leader:与其他共识算法不同,Raft使用一种更强的领导形式,追加日志的操作必须是连续的,先由Leader更新最新记录,再到其他服务器;
Leader选举:Raft使用随机时钟选择Leader,只有拥有最新、最全日志的节点才能够当选 Leader,从而简单快捷的解决选举过程中的冲突;
成员变更:当集群配置发生变更,如替换失效节点或做节点迁移时,Raft融入了配置变更自动化的理念保障分布式集群可以继续正常运行。
Raft算法定义了三种角色:leader、candidate 和 follower,其基本过程为:
Leader 选举:每个 candidate 随机经过一定时间都会提出选举方案,最近阶段中得票最多者被选为 leader;
同步事件发生记录的log:leader 会找到系统中 log 最新的记录,并强制所有的 follower 来刷新到这个记录;
图3 Raft算法示意图
在上图的示例中,客户端Y和Z分别请求服务器S3,S5的提案都会被转发给Leader服务器S1,S1会处理这些提案,然后其他的服务器都是Follower。Leader服务器会有最全最新的记录。
1.6 共识算法
区块链是一种分布式的网络系统,分布式系统最为关键的问题就是“一致性的问题”。分布式系统中多个网络节点必须达成一致,而这个一致又必须是要在一定约束操作和规定协议的前提下使得所有的网络节点的处理结果达成规定协议的一致。
这种一致性规定协议在区块链中称为共识算法。我们可以说共识算法是区块链的灵魂。没办法达成共识,或者共识算法被修改,有可能导致信任出现危机,不利于区块链的发展,现在一些数字货币就存在这样的情况。
区块链的共识算法与传统分布式一致性算法相比,传统的分布式算法并不考虑拜占庭容错,只假设所有节点仅发生宕机、网络故障等非人为问题,没有考虑恶意节点。传统分布式一致性算法面向数据库或文件,而区块链共识算法面向交易或价值传输,甚至存在恶意节点故意要破坏系统的情况。一般地,把故障(不响应)的情况称为“非拜占庭错误”,恶意响应的情况称为“拜占庭错误”(对应节点为拜占庭节点)。
1.6.1 拜占庭问题
拜占庭问题讨论的是允许存在少数节点作恶(消息可能被伪造)场景下的一致性达成问题。拜占庭问题又叫拜占庭将军(Byzantine Generals Problem)问题,是 Leslie Lamport 1982 年提出用来解释一致性问题的一个虚构模型。
图4 拜占庭将军问题示意图
拜占庭是东罗马帝国的首都,在首都周边有众多将军负责城防,将军之间通过信使来传递消息,达成某些一致的决定。这些将军在地理上是分隔开来的,并且将军中存在叛徒。叛徒会想尽一切办法干扰一致性的达成,从而实现攻击。拜占庭问题即为在此情况下,如何让忠诚的将军们能达成行动的一致。
拜占庭假设是对现实世界的模型化,由于硬件错误、网络故障以及遭到恶意攻击,分布式网络可能出现无法预料的行为。拜占庭容错协议必须处理这些失效,并且这些协议还要满足所要解决的问题要求的规范。这些算法通常以其弹性t作为特征,t表示算法可以应付的错误进程数。很多经典算法问题只有在n ≥ 3t+1时才有解,拜占庭将军问题也是,其中n是系统中进程的总数。
拜占庭问题之所以难解有两方面的原因,一是由于提案成本很低,任何时候系统中都可能存在多个提案。另外要完成对提案的最终一致性确认十分困难,容易受干扰。
1.6.2 工作量证明(PoW: Proof of Work)
工作量证明是一个协议,在比特币之前就已经存在,PoW 的想法最初是由 Cynthia Dwork 和 Moni Naor 于 1993 年提出,在Adam Back的 Hashcash里也有体现。根据中本聪的设想,PoW的主要目标是阻止网络攻击,例如分布式拒绝服务攻击(DDoS)。矿工将交易打包进候选区块后,下一步就要计算这个区块头的哈希值,它确定一个数(nonce),通过不断修改nonce(通常是增加一个bit),使区块数据的加密哈希算法的结果小于给定的阈值。基于目前比特币网络的计算难度,一个挖矿节点需要尝试数亿次的计算才能找到符合要求的nonce。
正是由于消耗了大量算力来满足PoW算法的要求,每一个区块的生成都代表了矿工在验证交易、交易打包和生成区块的过程中所付出的成本。如果有黑客尝试修改区块中的交易数据,就需要付出同等的工作量,同时由于块链式数据结构的特性,还需要付出修改这个区块后面所有区块的算力。工作量证明有效保证了比特币的分布式共识,即不依托一个中心化的权威机构来完成节点之间的交易和记账,最终实现了比特币系统的自治。
优点:
结构简明扼要、有效可靠,节点间无需交换额外的信息即可达成共识;
某种程度上是公平的,投入的算力越多,获得打包权的机率也等比增加;
去中心化,将记账权公平的分派到其他节点。你能够获得的币的数量,取决于你挖矿贡献的有效工作,也就是说,你用于挖矿的矿机的性能越好,分给你的收益就会越多,这就是根据你的工作证明来执行币的分配方式;
安全性高,破坏系统需要投入极大的成本,如果想作弊,要有压倒大多数人的算力(51%攻击)。因为作弊要付出一定成本,作弊者就会谨慎对待了。在比特币的 PoW 机制中,由于获得计算结果的概率趋近于所占算力比例,因此在不掌握51%以上算力的前提下,矿工欺诈的成本要显著高于诚实挖矿,甚至不可能完成欺诈(由于概率过低)。
缺点:
网络性能太低,需要等待多个确认,容易产生分叉,区块的确认共识达成的周期较长(10分钟),现在每秒交易量上限是7笔(visa的平均每秒交易量上万,支付宝峰值接近11万),不适合商业应用;
永远没有最终性,需要检查点机制来弥补最终性;
非常浪费能源,投入在一种加密货币上的能源(电力),可能会超过一个小型国家的总使用量;
算力垄断,例如比特大陆在比特币矿机和 ASIC 芯片领域拥有 70-80% 的市场份额,全网算力被其高度垄断。这与加密货币的去中心化思想背道而驰。从比特币扩容之争可以看到,算力高的大型矿池是主人,而持币的人没有参与决定的权利;
51%攻击,只要掌握了51%的算力,就有能力对系统产生攻击,2018年5月底,一名恶意矿工临时获得了51%的算力,利用双花漏洞,对比特币黄金网络发动攻击,窃取了价值高达1860万美元的资金。
1.6.3 权益证明(PoS: Proof of Stake)
权益证明是一种验证交易的方式,通过选举的形式,任意节点都可以被随机选择来验证下一个区块。与工作量证明奖励矿工解决数学问题来验证交易不同,权益证明中没有矿工,只有验证者(validator)。验证者并不是被完全随机选择的,要成为验证者,节点需要在网络中存入一定数量的数字货币作为权益,可以理解为保证金。权益的份额大小决定了节点被选为验证者的几率。验证者将通过验证的交易打包来"铸造(mint)” 或"制造(forge)”新区块,区块加入到链上后,验证者会获得交易费作为奖励。交易费不会大于节点抵押的权益,从而确保验证者可以持续工作。一段时间后,如果节点放弃验证者的工作,会把权益和所有交易费奖励返还给节点。这需要在区块确认完成一段时间后返还,以防止验证者打包虚假交易。
相比工作量证明,PoS共识更加的去中心化,同时成本更低。目前比特币网络超过80%的算力被几大矿池控制,持币的人没有参与记账的权利。而PoS没有挖矿的概念,只有被选举出来的节点才能参与记账。而节点选举除了考虑权益,还需考虑节点的币龄(持币时间)和其他因素,从而最大程度的保证公平。比特币的工作量证明算法需要全网所有节点来验证交易,而PoS则只需要部分节点作为验证者,同时构建节点的成本相比比特币挖矿设备也非常低。
目前使用PoS共识算法的有Peercoin Lisk和Nxt等数字货币项目,以太坊也正在开发一种权益证明系统(Casper)。
优点:
更加去中心化;
交易确认和区块生成更快,更高的TPS;
成本较低,无需昂贵的挖矿设备,能源消耗低。
缺点:
验证者的选举策略有待完善,选举出来的验证者有可能消极怠工;
每次选举时大量节点的网络通信对网络压力极大;
极端的情况下会带来中心化的结果,PoS的安全取决于权益持有者,所以持有权益较多的节点仍然存在51%攻击的漏洞。
1.6.4 委任权益证明(DPoS: Delegated Proof of Stake)
委任权益证明也是一种去中心化共识算法。基础原理是持有Token的人可以通过投票系统持续选择区块生产者(Block Producer),任何人都可以成为块生产者,只要他能说服其他Token持有人以获得足够投票。仅一个块生产者被授权能在给定的时间点生产区块。如果在预定时间内没有生成,则跳过该块。如果生产者错过了一个块,并且在过去24小时均未生产任何块,则会被删除,直至其向区块链通知打算再次生产块。通过排除不可靠的生产者,使得遗漏的区块数量实现最小化,确保网络的顺畅运行。
理论上, DPoS区块链不会经历任何分叉,因为其区块生产过程中,生产者是合作而不是竞争关系。如果有分叉,共识将自动切换到最长的链上。其工作原理是,共识机制下,将新区块添加到分叉区块链中的速度是与分叉链中的生产者的占比直接相关的。换言之,拥有较多生产者的区块链分叉会比生产者少的链增长速度要快得多,因为生产者占比越高的分叉链丢失的区块会更少。此外,任何块生产者都不应该同时在两个分叉上生产块。如果有块生产者被发现这么做,可能会被投票出局。
目前使用DPoS共识算法的项目有EOS(Enterprise Operation System),在DPOS基础上,EOS中加入了异步拜占庭容错(aBFT),可以实现更快的交易确认和区块生成。
优点:
能源消耗少
网络资源消耗少
共识时间短
吞吐量高
缺点:
实现较为复杂
中间步骤较多,容易产生安全漏洞
整个共识机制还是依赖于代币,很多商业应用是不需要代币存在的。
1.6.5 实用拜占庭容错(PBFT:Practical Byzantine
FaultTolerance)
PBFT算法是Miguel Castro (卡斯特罗)和Barbara Liskov(利斯科夫)在1999年提出的,解决了原始拜占庭容错算法效率不高的问题。PBFT算法的提出是在网络恶意攻击和软件错误不断增多的背景下,失效节点可能产生任意行为。PBFT是一种状态机副本复制算法,即服务作为状态机进行建模,状态机在分布式系统的不同节点进行副本复制。每个状态机的副本都保存了服务的状态,同时也实现了服务的操作。
PBFT算法在保证活性和安全性(liveness & safety)的前提下提供了(n-1)/3的容错性,即网络中有(n-1)/3个节点同时失效,系统依然可以正常运行。活性指所有客户端最终都会收到针对他们请求的回复。安全性是指副本复制服务满足线性一致性(linearizability),可以像中心化系统一样执行原子化操作。
实用拜占庭容错机制是一种采用“许可投票、少数服从多数”来选举主节点并进行记账的共识机制。相比早期拜占庭容错算法,PBFT性能更高同时耗能更低,而且每轮记账都会由全网所有节点共同选举领导者。容错率为33%,只要系统中有2/3的节点是正常工作的,就可以保证一致性。
下图展示了正常情况下,即主节点没有失效时PBFT算法的运行过程。
图5 PBFT算法运行过程
其中副本0是主节点,副本3是故障节点,C是客户端,运行过程如下:
1)客户端发送请求,激活主节点0的服务操作;
2)主节点收到请求后,启动三阶段的协议向其他备份节点广播请求;
预准备(pre-prepare)阶段,主节点给请求赋值一个序列号n,广播序列号分配消息和客户端的请求消息m,并将构造pre-prepare消息给备份节点;
准备(prepare)阶段,备份节点接受pre-prepare消息,每个节点向其他节点广播prepare消息;
确认(commit)阶段,各节点对请求和序列号进行验证后,广播commit消息,执行客户端发来的请求并给客户端响应。
3)客户端等待来自不同节点的响应,若有2f+1个响应相同(f为网络中总的故障节点个数),则该响应即为请求的结果。
在区块链系统中,由于设计目标和应用场景不同,共识算法的选择也各有千秋。可信环境使用Paxos或者Raft,节点许可的联盟可使用PBFT ,非许可的公有链可以是PoW、PoS和DPoS等共识算法。Hyperledger Fabric将共识机制设计成可插拔的模块化,支持像PBFT、Raft等共识算法。
1.6.6 Algorand 拜占庭共识
Algorand共识算法是图灵奖得主SilvioMicali教授于2017年提出的,使用一种新的拜占庭协议(BA*)来达成共识。
Algorand采用了VRF(Verifiable Random Function)可验证随机函数,并结合账户的余额比例,随机确定区块生成以及投票人角色。VRF提供了一个随机数生成方法,而且这个随机过程和私钥有关,并可以通过公钥被验证。使用这个随机数,从一群大范围的验证者中选取一部分验证者运行BFT算法(即BA*算法),从而达到提高共识的效果。
BA*共识算法的执行分为两个阶段:1)同步确认最高优先级区块 2)对生成区块的共识协议进行确认。每个阶段又包含几个交互的步骤,每个步骤中参与投票的用户(committee member)采用密码学抽签,每一轮参与投票的用户都可以证明确实是随机选取的。
BA*共识算法将出块流程,分级共识协议(GC: Graded Consensus Protocol)和二元拜占庭共识协议 (The Binary BA Protocol BBA*)串联在一起,最后完成出块流程。当每一轮投票结束时,都满足:
一致性(Consistency):所有诚实用户都通过同一个验证算法达成共识;
共识性(Agreement):所有诚实用户要么都发生共识,要么都不发生共识。
正常情况下,当分布式网络是强同步并且最高优先级区块是由诚实节点打包,BA*通过最后一轮确认的区块来达成最终共识。为了提升共识效率,在投票过程中,节点仅对区块hash进行投票确认,并不验证整个块的内容。
BA*共识算法解决了工作量证明出块慢、可能分叉等问题。Algorand论文中提到使用1000台EC2虚拟机,模拟50万用户的实验来评估算法性能,结果表明交易确认可以在1分钟内完成,吞吐量达到比特币的125倍。
Algorand采用VRF和密码学抽签的方式,提出了一个解决CAP“不可能三角”的非常好的设想,然而由于缺乏对网络延迟和实际应用中节点数量的考虑,在工程落地时依然存在网络规模和账本存储的限制。
1.7 本章小结
本章介绍了分布式系统领域的关键技术,首先简介了去中心化、分布式计算和分布式存储等基本概念,接下来对分布式系统的一致性,CAP原理,ACID原则、BASE理论和一致性算法进行了讲解。最后对常用的几种共识算法,如PoW、PoS、DPoS、PBFT和Algorand进行了分析,我们知道了不同共识算法的实现原理和关键算法的优缺点。
分布式原理是区块链的基石,另外区块链的发展还用到了其他很多概念和技术,我们将在本书接下来的章节继续深入学习了解。
网友评论