共识的含义
对于现实世界,共识就是一群人对一件或者多件事情达成一致的看法或者协议,在计算机世界,多个节点对某个数据达成一致共识,多个节点对多个数据的顺序达成一致共识。
共识算法的三大分类
- 私链:私链的共识算法即区块链这个概念还没普及时的传统分布式系统里的共识算法,私链的适用环境一般是不考虑集群中存在作恶节点,只考虑因为系统或者网络原因导致的故障节点,常见算法包括
raft,paxos
- 联盟链:联盟链的适用环境除了需要考虑集群中存在故障节点,还需要考虑集群中存在作恶节点,对于联盟链,每个新加入的节点都是需要验证和审核的,常见算法包括
pbft,dbft
- 公链:公链不断需要考虑网络中存在故障节点,还需要考虑作恶节点,这一点和联盟链是类似的,和联盟链最大的区别就是,公链中的节点可以很自由的加入或者退出,不需要严格的验证和审核,常见算法包括
pow,pos,dpos,ripple
Pow(Proof of Work)
概述
- 用一份证明来确认做过一定量的工作,工作方需要花费很长时间去得出一个结果,验证方可以很容易使用该结果来验证工作方的工作量
- 通过暴力破解方法解决一个数学难题,在哈希计算后得到一个小于目标值的哈希值
举例
给定一个字符串Hello, world!
,现在要求在该字符串后面加上一个nonce
的整数值,采用SHA256
哈希运算之后,哈希结果符合前4位是0,即结果是0000*
,则验证通过
可以采用python
代码实现如下
import hashlib
msg = "Hello, world!"
for i in range(1000_000_000):
result = hashlib.sha256(f'{msg}{i}'.encode()).hexdigest()
if result.startswith('0000'):
print(f'nonce: {i}, result: {result}')
break
上面的输出结果是
nonce: 4250, result: 0000c3af42fc31103f1fdc0151fa747ff87349a4714df7cc52ea464e12dcd4e9
上面为了计算出一个符合条件的哈希值,运算了4251次,得到了nonce
的值为4250,这样验证方就可以拿着一个Hello, world!
的信息,加上一个nonce
为4250的值,运算一次,得出的哈希结果就可以验证符合要求,证明了工作量
哈希函数主要说明与特征
- 输入
x
的长度任意,输出H(x)
的长度固定,计算H(x)
的过程是高效的 - 免碰撞,哈希函数的输出需要足够随机,即不会出现输入
x≠y
,但是H(x)=H(y)
。比特币采用的SHA256
算法,输出长度是256,输出可能性就是2^256,所以当输入2^256+1次,则必然产生一次碰撞,但是现实中,运算2^32大概是40亿次,运算2^256次是压根就没法计算完的。 - 不可逆性,即根据一个输出
H(x)
,不能倒推回输入x
应用
PoW
是比特币的共识机制,在目前的公链共识算法里面占据主导地位,矿工以计算机计算工作,获取相应的比特币奖励或者手续费,将一些列的交易打包形成块,矿工采用SHA-256
算法,计算其块的hash值进行验证,
安全性分析
一个破坏者拥有比特币全网算力的51%,即可以改写区块链进行欺骗,但是新区块的产生同时也会有新币奖励以及交易费的收取,这在一定程度上保护了比特币网络的安全,即攻击者会在使用高昂的算力进行欺骗以及使用算力生产新区块获取新币以及交易费之间做出选择。(但是也不排除现实中会存在一种人,就是不在乎利益的,就像功夫里面的火云邪神一样,只是想找个对手,最经典的就是对着杨过与小龙女所说的经典台词,我只是想...)
优点
- 造假成本比较高
缺点
- 资源浪费,挖矿需要大量的哈希运算,消耗大量资源,找到的哈希值的唯一意义就是满足了挖矿成功的定义,即该哈希的有多少个连续的0作为开头,除了使恶意攻击者不能轻易地伪装成几百万个节点和打垮比特币网络,并没有更多实际或科学价值
- 网络性能低,因为
PoW
共识算法限制比特币出块的时间是10分钟,所以交易确认至少需要10分钟,而且目前仅支持每秒7笔的交易速度,不适合高并发的商业应用 PoW
共识算法算力集中化,目前挖矿矿池是主力,个人矿工基本不可能生存下去,算力高的矿池有选择权,进而导致算力的集中化- 随着比特币产量的不断降低, 矿工人数也会越来越少, 这样就会导致整个比特币网络的稳定性出现问题,矿工数量变少的时候,比特币被51%算力攻击就越容易
算法矛盾点
区块大小与出块间隔。增加区块容量可以提高吞吐量,但是区块过大会造成网络拥塞,增加节点间共识的时间和效率,反而可能降低区块效率;减小出块间隔也能增加吞吐量,但出块间隔的缩短会造成更频繁的链分叉,也会增加双花等安全问题
Pos(Proof of Stake)
概述
基于随机选择的验证者来生产并批准区块,验证者通过在区块链内锁定代币来“质押”原生网络代币,验证者根据自己的权益质押总额获得奖励,此举可以用投资回报 (ROI
) 来激励节点验证网络,类似现实生活中的股东机制,拥有股份越多的人越容易获取记账权,同时越倾向于维护网络的正常工作,是更加环保和更加可扩展的共识算法
区块生产过程
- 被选出的验证者根据自己的权益质押情况产出下一个区块
- 权益质押数额较大的验证者生成下个区块的机会更大
- 区块先由部分验证者提交,然后向其他验证者播送,由这些验证者核实后将获得批准的区块添加到区块链
实现逻辑
- 通过保证金( 代币、资产、名声等具备价值属性的物品) 来对赌一个合法的块成为新的区块,收益为抵押资本的利息和交易服务费
- 提供证明的保证金,例如通过转账货币记录越多,则获得记账权的概率就越大
- 恶意参与者的恶意操作并生成虚假区块,为了生成区块而按照锁定机制所质押的权益就会面临着遭到削减或被剥夺控制权的威胁(保证金被罚没,即损失经济利益),对于
PoS
来说,需要掌握超过全网 1/3 的资源,才有可能左右最终的结果 - 在
POS
模式下, 有一个概念叫币龄, 每个币每天产生1币龄, 例如,你持有 100 个币, 总共持有了 30 天, 那么, 此时你的币龄就为 3000, 这个时候, 如果你发现了一个PoS
区块, 你的币龄就会被清空为 0。 你每被清空 365币龄, 你将会从区块中获得0.05个币的利息( 可以理解为年利率5%) , 那么在这个案例中, 利息=3000×5%/365=0.41
个币
加密货币所有者获得的好处
- 持有奖励:用户只需让加密货币在自己的钱包里放上一段时间,即可赚取奖励
- 参与/委托奖励: 用户将自己的部分权益委托给负责保护网络的验证者。 验证者与委托权益给自己的用户分享部分权益质押收入,由此产生奖励
优点
- 省资源:不需要挖矿,不需要大量耗费电力和能源
- 更加去中心化:相对于比特币等
PoW
类型的加密货币,更加去中心化,相比PoW
算法的51%算力攻击,PoS
需要购买51%的货币,成本更高,没有攻击意义 - 避免通货膨胀:
PoS
机制的加密货币按一定的年利率新增货币,可以有效避免紧缩出现,保持基本稳定
缺点
POS
会面临发币的问题,起初只有创世块上有币,意味着只有这个节点可以挖矿,所以让币分散出去才能让网络壮大,所以早期采取的是POW+POS
,即第一阶段POW
挖矿,第二阶段POS
挖矿,后来ERC20
合约代币出现后,可以只存在POS
的挖矿形式- 开发者作恶,纯
PoS
机制的加密货币,只能通过IPO
的方式发行,这就导致“少数人”(通常是开发者)获得大量成本极低的加密货币,很有可能造成大面积的抛售 - 币龄其实就是时间,一旦挖矿者囤积一定的币,很久很久之后发起攻击,这样将很容易拿到记账权
- 矿工可以囤积代币从而导致货币流通困难
POS
面临的最严重的一个问题就是无成本利益问题,在PoS系统中做任何事几乎没有成本,比如在PoS
系统上挖矿几乎没有成本,这也就意味着分叉非常方便- 首富账户的权力过大,可能支配记账权
Dpos(Delegated Proof of Stake)
概述
DPO
S是一种基于投票选举的共识算法,有点像民主大会,持币人选出几个代表节点来运营网络,用专业运行的网络服务器来保证区块链网络的安全和性能,DPOS
机制中,不需要算力解决数学难题,而是由持币者选出谁说生产者,如果生产者不称职,就有随时有可能被投票出局,这也就解决了POS
的性能问题
受托人,代理人(Delegates)的主要职责
- 保证节点的正常运行
- 收集网络里的交易
- 节点验证交易,把交易打包到区块
- 节点广播区块,其他节点验证后把区块添加到自己的数据库
- 带领并促进区块链项目的发展
实现逻辑
- 受托人的节点服务器相当于比特币网络里的矿机,在完成本职工作的同时可以领取区块奖励和交易的手续费
- 一个区块链项目的受托人个数由项目发起方决定
- 任何一个持币用户都可以参与到投票和竞选受托人这两个过程中,用户可以随时投票、撤票,每个用户投票的权重和自己的持币量成正比
- 投票和撤票可以随时进行,在每一轮选举结束后,得票率最高的
n
(区块链项目方决定)个用户则成为该项目的受托人,负责打包区块、维持系统的运转并获得相应的奖励 - 每名代表都有一份相等的投票权,并且,如果当前记账节点不记账则由下一个记账人记账
DPOS
机制的原则
- 持股人依据所持股份行使表决权,而不是依赖挖矿竞争记账权
- 最大化持股人的盈利
- 最小化维护网络安全的费用
- 最大化网络的效能
- 最小化运行网络的成本
PBFT(Practical Byzantine Fault Tolerance)
背景
拜占庭罗马帝国国土辽阔,为了达到防御目的,每块封地都驻扎一支由将军统领的军队,每个军队都分隔很远,将军与将军之间只能靠信差传递消息。 在战争的时候,拜占庭军队内所有将军必需达成一致的共识,决定是否有赢的机会才去攻打敌人的阵营。但是,在军队内有可能存有叛徒和敌军的间谍,左右将军们的决定影响将军们达成一致共识。在已知有将军是叛徒的情况下,其余忠诚的将军如何达成一致协议的问题,这就是拜占庭将军问题。
必要前提
信道必须是可靠的,如果信道不能保证可靠,在一个不可靠的通信链路上试图通过通信以达成一致是基本不可能或者十分困难的
算法基本解释
将军总数大于 3f
,背叛者为f
或者更少时,忠诚的将军可以达成命令上的一致,即 3f+1<=n
,即网络中全部节点总数是大于3f
,恶意节点以及故障节点总数是小于等于f
,那么整个集群还是可以达成一个正确的共识,该算法最大容错节点数量是(n -1)/3
,算法需要支持容错故障节点,也需要支持容错作恶节点
最好极端情况
如果f
个节点是故障节点,也是作恶节点,那么根据少数服从多数的原则,集群里面存在f+1
个正常节点,那么集群就能够达成共识,这种情况支持的最大容错节点数量是 (n-1)/2
最坏极端情况
故障节点和作恶节点全是不同节点,有f
个作恶节点,有f
个故障节点,当发现节点是作恶节点之后,集群排除节点,剩下f
个故障节点,根据少数服从多数原则,需要f+1
个正常节点大于f
个故障节点,集群就能达到共识,所以最大容错节点是(n-1)/3
优点
- 通信复杂度
O(n^2)
,解决了原始拜占庭容错(BFT
)算法效率不高的问题,将算法复杂度由指数级降低到多项式级,使得拜占庭容错算法在实际系统应用中变得可行 - 首次提出在异步网络环境下使用状态机副本复制协议,该算法可以工作在异步环境中,并且通过优化在早期算法的基础上把响应性能提升了一个数量级以上。作者使用这个算法实现了拜占庭容错的网络文件系
NFS
,性能测试证明了该系统仅比无副本复制的标准NFS慢了3% - 使用了加密技术来防止欺骗攻击和重播攻击,以及检测被破坏的消息。消息包含了公钥签名(
RSA
算法)、消息验证编码MAC
和无碰撞哈希函数生成的消息摘要
缺点
- 仅仅适用于联盟链/私有链
- 通信复杂度过高,可拓展性比较低,一般的系统在达到100左右的节点个数时,性能下降非常快
- 在网络不稳定的情况下延迟很高
Raft
概述
将一致性问题看成系统中进程间在不同机器上一个状态机同步问题,为保证每个机器上的进程具有一致性,Raft
共识算法来保证在每个进程初始状态相同的情况下,每个进程的下一个操作,状态改变操作相同,这样就能保证所有进程的状态机的改变过程是一样的,即系统中的进程最终会达成数据一致状态
raft
集群节点状态
leader
领导者,负责整个集群状态的同步和对外部事件的处理,整个集群只有一个leader
follower
跟随者,是被动的,不会主动发出消息,只是响应leader
或candidate
的消息,或者转发客户端的请求给leader
candidate
候选者,是一种临时的状态
领导人选举
- 每个节点在加入集群的时候都会初始化为
follower
- 当前集群没有
leader
的时候,follower
会进行选举试图成为leader
,将自己的状态转变为candidate
- 向集群内的其他成员发起投票请求,若该
candidate
收到了大多数人的赞成票 - 变成
leader
之后,集群内广播心跳消息,接到心跳消息的follower
或其他candidate
就会认识到此时已有leader
,会停止自己的竞选行为而重新变为follower
,稳定的集群状态就形成了
发起竞选条件
每个节点内部都有一个被称之为选举时停的属性,当在此时间段内,没有收到来自leader
的心跳消息,就可以认为当前没有leader
存在,可以发起竞选
任期term
概念
- 任期
Term
是一个全局可见递增的数字 - 几乎每个在集群间传播的消息都会携带者发送者所属的
Term
- 表示一个
Leader
发挥其影响力的一段时期的序号 Term
的增加发生在一个follower
成为candidate
时,一个follower
长时间未收到leader
的心跳,它就认为新的时代要到来了,因此它自增此Term
,成为候选者发起竞选,同时将此更新后的Term
发送给其他节点以彰显自己的竞选资格
日志序号Index概念
- 纪录了节点日志
entry
的序号
follower
投票给candidate
的条件
- 投票的原则是先来先投票
- 在一个
Term
内只能投一次赞成票,如若下一个来请求投票的candidate
的Term
更大(表示可能进入到了下一轮的选举),那么投票者会重置自己的Term
为最新然后重新投票 candidate
的日志index
大于自己的日志index
candidate
的term
大于自身的term
选举失败后续流程
candidate
的选举活动有一个最大时限,超过该时限还没有成功胜出,就会被宣布为失败,重新变为follower
然后重新开始选举时停的计时,为了保证选票瓜分的情况不会频繁出现,每一个节点的选举时停都是随机的
日志复制阶段
- 提案阶段:是一个初始阶段,当
leader
收到来自客户端的一条请求后,会将请求打包成为一个entry
,该entry
便处于此阶段,它是不稳定的,也就是说集群没有办法保证此entry
会被集群接受还是抛弃(网络、机器原因),需要raft
共识算法发挥其作用来确定 - 达成共识阶段/可提交阶段:一旦某一
entry
被集群内大多数节点所持有,该entry
就已经处于达成共识阶段,它已经能够确定将会被集群接受(提交),但具体何时写入状态机,外部客户端何时能够验证此命令已经生效,则是没有办法保证的 - 被提交阶段:可认为是显式的达成共识阶段。当
leader
意识到某一个entry
已经进入了达成共识阶段,则leader
将会将它标记为被提交状态。并将此信息广播给集群中的其他节点声明该entry
已经被集群接受,可以将其应用进状态机了 - 被应用状态:当集群中的任意节点意识到某一个
entry
已经被标记为已提交,而且自身也持有这个entry
,就会将其应用进状态机,对于KV
数据库可能是写、删除操作等,此时一个请求才真正被完成,可以被外部验证其已被执行
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。