赞
踩
区块链基本概念和名词解释
P2P
共识算法
梅克尔-帕特里夏树
从零开始搭建区块链
前文已经说过,区块链从本质上来说就是基于P2P网络的分布式系统,而对于分布式系统来说,如何维护各节点之间的状态尤其重要,需要所有节点步调一致,这就需要设计相应的算法或者协议来进行管理。对于一个分布式系统来说,一定是遵从CAP定理的
要实现一致性,必然需要经历共识的过程
,所以共识算法可以简单看作是一致性算法的一个步骤。全称是Proof Of Work,即工作量证明。前文我们已经讲过了POW简单来说就是解数学题,通过不断地计算,最终得出正确答案的过程。
输入数据是 “自增数+该区块的Hash”,由于没办法预测输出结果,且区块的Hash是定值,所以只能不断的用自增数去试,直到试出这个答案来
仅仅是这样就能实现POW算法了吗?其实上面计算nonce只是算法的一部分,该算法还约定了所有节点总是倾向于选择更长链,即使用更长链的hash作为previousHash的区块,以及只要这几个条件都满足了要无条件接受。只有以上几点同时满足,POW算法才能正常工作。
接下来再针对几个维度看看POW算法的表现如何
正如上面提到POW算法由于非常的不环保,催生了很多更加环保的共识算法,其中就有POS,Proof Of Stake,即权益证明算法。这个算法也没有过多的数学论证,更多的是一种设计思想上的创新。既然POW是率先算出答案的才有绝对话语权,会让参与区块链的用户陷入无尽的算力之争,那就让你直接不用算了,而是通过 “购买股份” 的方式来决定你的相对话语权。
可以想象成现实生活中我们使用金钱去购买某家公司的股权,占的股比越高在股东大会上的话语权也就越高。而放在区块链的世界中,其典型的实践就是通过质押代币来实现购买股份的目的,谁购买的代币越多谁的话语权就更高,也就更容易被推选出来作为记账者。如果被选举成为记账者,但是被发现作恶时,则会按照其行为扣除其质押的代币,来一定程度上遏制作恶行为的产生。
正是这样简单的机制,就避免了前面提到的能源浪费问题。但是POS也有一些缺点,比如在区块链运行前期少数人才能挖矿,因为代币都集中在少数人手里。还有很容易造成矿工囤积代币,以期获得更多的记账权,进而造成代币越来越向更多持有者集中(有点像现实生活中的马太效应,钱越来越向少数富人集中)。
前面提到的算法都是有效适用于海量节点的,也就是公链很适合使用的,但是忽略了一个使用场景就是联盟链和私链。这种场景的节点数一般较少,且一般需要进行身份验证,所以对于共识算法来说就可以不依赖现实生活中的资源(如算力、代币)作为因素来进行,可以通过节点间纯通信来实现强一致性。这种类型的算法往往需要全节点协商参与共识,就必然涉及到节点间的通信,在通信过程中如果节点数过多通信的次数过多,则很容易出现网络风暴进而造成整个网络瘫痪。
PBFT即Practical Byzantine Fault Tolerance,意为实用拜占庭容错算法,在将这个算法前有必要先说一下什么是拜占庭容错,而这就是为了解决著名的拜占庭将军问题
拜占庭是一个地名,位于如今的土耳其的伊斯坦布尔,在古代是东罗马帝国的首都。由于当时拜占庭罗马帝国国土辽阔,为了达到防御目的,每个军队都分隔很远,将军与将军之间只能靠信差传消息。在战争的时候,拜占庭军队内所有将军和副官必须达成一致的共识,决定是否有赢的机会才去攻打敌人的阵营。但是,在军队内有可能存有叛徒和敌军的间谍,左右将军们的决定又扰乱整体军队的秩序。在进行共识时,结果并不代表大多数人的意见。这时候,在已知有成员谋反的情况下,其余忠诚的将军在不受叛徒的影响下如何达成一致的协议,拜占庭问题就此形成。
而拜占庭容错,是由Leslie Lamport在其论文中提出的分布式对等网络通信容错问题。在分布式计算中,不同的计算机通过通讯交换信息达成共识而按照同一套协作策略行动。但有时候,系统中的成员计算机可能出错而发送错误的信息,用于传递信息的通讯网络也可能导致信息损坏,使得网络中不同的成员关于全体协作的策略得出不同结论,从而破坏系统一致性。
首先来看一看PBFT算法的几个步骤示意图
简单解释下,C代表客户端,0、1、2、3代表服务节点(其中0表示主节点)。整个算法执行过程中共产生5个状态跃迁,request -> pre-prepare -> prepare -> commit -> reply,有点类似于分布式事务中的二阶段提交。接下来分别对每个阶段展开说明:
这里面涉及几个问题:
上面介绍的PBFT算法在消息复杂度上比较高,因为其设计的是三阶段共识,那有没有复杂度相对低一点的共识算法呢,就是本节的主角Raft。对于Raft大家应该都熟悉,因为它常常被用作各大中间件的一致性算法,如Zookeeper、Elasticsearch、Redis等。
Raft将节点分为三种状态,分别是Follower、Candidate、Leader
设想一个场景,Leader所在的主机网络突然故障了,导致心跳包没能及时广播到Follower节点,所以Follower节点们纷纷超时后切换为Candidate节点发起了竞选Leader的投票并成功选出了一个新Leader,此时原Leader的网络恢复了,会发生怎样的后果呢?Raft中有个Term的概念即任期,每一个Leader都有属于自己的任期,而任期又始终是自增的。所以回到这个场景中,原Leader的任期肯定是小于新Leader的任期的,所以当原Leader收到新Leader的广播消息后会自动把自己降级为Follower,有效避免了冲突。
Raft的处理过程并没有引入二阶段提交,甚至是三阶段提交的机制,因为Raft是“一言堂”所有的事儿只需要听大哥安排就好。具体的事务在Raft中被视为一个个的“日志”,它是通过日志复制来进行一致性处理的。
每条日志都包含有索引号以及产生时的任期号,是按顺序排列的,一旦某条日志以及被复制到超过半数的节点上,则表示该日志已经被提交,即可以对客户端进行响应了。分布式系统中突然的网络中断是不可避免地,在出现频繁的复制失败、Leader选举之后,节点之间的日志存储情况可能天差地别,如下图所示。
每一个方块表示一个日志条目,里面的数字表示任期号,按照日志索引号顺序排列着的,这里面就包含了如下异常情况:
这种情况下,Raft会怎么处理呢?Leader节点会根据自身的最大索引日志向其他所有节点进行AppendEntry RPC操作,内容包含最大日志的索引号,而收到的节点如果发现和前一日志索引号存在断层或不匹配则拒绝响应,Leader只要收到任意拒绝响应则将索引号前移一位后再次重试。所以针对上述情况是按照如下逻辑进行处理的。
那么问题又来了,按照上图的情况,假如当选的Leader是b,那岂不是很多日志都要被丢弃了? 还记得前面说过有个日志提交的概念吗,只要被复制到超过半数的节点上,该日志就属于提交状态的,是不会被覆盖的,现在可以讲Raft是如何实现这一机制的。在新Leader选举时还会有一个额外的条件,即拉票节点是否包含有最大已提交日志块,只有是的情况下才给其投票。可以看到任期6索引9就是被提交的最大日志块,所以这种情况下能当选Leader的,只有a、c、d以及当前Leader这四个几点可能会当选Leader,所以此情况下b不可能当选为Leader。
总来地说,Raft相对于PBFT高效且相对简单,但缺点是并不能容忍作恶节点。
随着区块链的热度越来越高,对于共识算法的研究也是越来越广泛深入,发明出的共识算法种类也是种类繁多。上文提到了,PBFT、Raft等强一致性算法无法适应海量节点数量,甚至上百个节点数性能就已严重受到影响,所以绝大部分还是围绕POX方向进行展开,因为区块链最大的应用场景还是公链,其节点数都是非常庞大的。目前已知的大致有:
算法种类还有很多就不一一列举了,如果有兴趣进一步了解的,可以跳转这篇文章进行查看。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。