从零开始设计一个共识算法——一场没有硝烟的战争

本文详细介绍了如何从零开始设计一个拜占庭容错的共识算法,涵盖概念澄清、加锁机制、现有算法对比(PBFT、Tendermint、Hotstuff)等内容。通过分析安全性、活性以及解决隐藏锁问题,揭示了共识算法的设计思路,旨在帮助读者深入理解分布式一致性的重要性及实现原理。
摘要由CSDN通过智能技术生成

目录

1. 拜占庭容错算法

1.1 前言

1.2 概念澄清

1.3 假设

1.4 安全性

1.5 活性

2. 隐藏锁问题

2.1 收集锁

2.2 广播所有锁

2.3 引入固定时延

2.4 增加一个阶段

2.5 方案总结

3. 现有算法对比

3.1 PBFT

3.2 Tendermint

3.3 Hotstuff

4. 总结

5. 附录

5.1 情况分析

5.2 隐藏锁问题

参考文献


1. 拜占庭容错算法

1.1 前言

在本文中,我们尝试从零开始设计一个拜占庭容错的共识算法。但由于本文是在阅读大量文献之后,思考整理得出的,难免会有“事后诸葛亮”的嫌疑,但这不要紧,我们的目的也不是真的为了设计一个全新的共识算法,而是站在设计者的角度,思考一个共识算法是如何一步步得出的。当然,在推理过程中,我们也会使用尽可能少的已知条件,让“从零开始”不那么“哗众取宠”。在文章的后半部分,我们会在前文的基础上,分析对比 PBFT、Tendermint、Hotstuff 这三个共识的共性和差异。相信本文会让你对共识算法有一个较为全面的理解,以后如果遇到新的共识算法,也可以使用本文的思路分析,快速拿下。

1.2 概念澄清

在开始之前,我们先理清一些基本概念。

分布式一致性算法(共识算法):使集群中多个节点保持数据状态一致的通信算法。

拜占庭错误:节点除了宕机(不发送消息),还可能出现随机的恶意行为(发送假消息)。

拜占庭容错算法:能够容忍拜占庭错误的共识算法。设集群中拜占庭节点(错误节点)数为 f,当总结点数 N < 3f+1 时,不存在一个拜占庭容错算法。即总节点的最小数量为 3f+1,本文我们使用这个数量作为总节点的数量。

共识算法的正确性可以分为以下两个性质:

  1. 安全性 (safety),也叫一致性 (agreement),表示 所有正确节点执行的请求(包括顺序)一致
  2. 活性 (liveness),也叫可终止性 (termination),表示 共识总能在有限时间内达成

换句话说,如果没有安全性,不同节点就可能执行了不同请求,使系统失去了一致性,这是不可容忍的;如果没有活性,那么系统会永远“卡住”,无法处理请求。下面我们从这两个特性出发,尝试站在设计者的角度看一个拜占庭容错的共识算法是如何诞生的。

1.3 假设

为了让算法在可证明正确性的同时可被实际应用,我们需要在特定的网络下设计算法。存在以下几个网络模型:

  1. 同步(asynchrony):网络延迟存在一个已知的固定上限 Δ。即消息总能在 Δ 时间内传输到目标节点。
  2. 异步(synchrony):网络延迟不存在固定上限 Δ。即消息不一定能在固定时间内传输到目标节点。
  3. 部分同步(partially synchrony):网络延迟固定上限 Δ 已知,但仅在一个未知的时间 GST(global stabilization time) 后成立。也就是在 GST 之后,网络为同步网络。当然,同步网络不会永远保持,只会保持一定时间,所以部分同步可以看成是异步网络和同步网络交替进行的网络模型。

实际的网络可能存在丢包、分区等情况,所以不是一个同步的网络;而在异步网络下,无法保证活性;部分同步网络最符合实际,因此我们算法的设计将会基于这个假设。

我们需要设计一个这样的共识算法:即使是在异步网络下,也要保证安全性;在同步网络下,保证活性。这样,在部分同步网络下,就能保证算法的安全性和活性。

分布式一致性算法早在上个世纪就被广泛研究,但随着区块链的兴起,再次进入人们的视野。为了方便讨论,同时使共识算法更贴近于区块链的场景,我们把算法的一些参数对应到区块链中,把“请求”称为“区块”,请求的执行顺序称为“高度”,区块按照高度顺序串联起来就成了区块链。但请记住,共识算法并不关心请求是什么,不同系统可以有不同的请求结构。

同时,我们假设共识为单线程的,即只有完成上一个区块的共识,才能开始下一个区块的共识。并且我们假设存在某个机制,当节点发现自身区块落后于其他节点时,会自动从其他节点同步,本文不对这个机制做具体描述,并简单使用“快速恢复机制”来指代这个过程。

1.4 安全性

如何共识?

系统如何对一个高度的区块达成共识呢?这可以类比一个民主的组织如何达成一个决策,往往会有一个提案者(proposer,为了便于讨论,我们暂且称为 leader)提出一个方案,其他成员进行投票表决。对应到共识算法中,我们需要选出一个 leader,对于某个高度,(收集交易并)组装区块(这个过程我们简称为“出块”,组装好的含高度的区块我们称为“提案”)并广播,其它节点收到的提案后广播投票,收集其他节点的投票,当收集到足够多的相同投票时,确定该提案。

收集多少投票?

由于有 f 个拜占庭可能不投票,所以收集到 2f+1 个投票就该停止,否则系统将失去活性。由此我们给节点引入一个行为:

行为1:节点收集到 2f+1 个相同投票(含提案)时,提交该提案,执行区块并存储,最后向客户端响应。

加锁

另外,由于 leader 可能为错误节点,可能故意向不同节点发送不同提案(同一高度的不同区块),所以为了保证安全性,正确节点只会对某个高度投一票,即当高度 H 已经给区块 A 投过票时,不会再对该高度的其他区块投票,我们称这个行为为“加锁”,并且说节点对于高度 H “锁定”在了区块 A。

由此,我们引入第二个行为限制:

行为2:对于某个高度,正确节点发起或收到一个提案时,会锁定该区块,并坚持对已锁定的区块进行提案或投票,而会忽略该高度下的其他区块提案。

QC 性质

有了加锁机制之后,不同节点还有没有可能在同一高度提交不同区块呢?

稍加推理,我们会发现这是不可能的:假设在高度 H 上,节点 1 提交了区块 A,节点 2 提交了区块 B。那么说明有 2f+1 个节点对区块 A 投了票,有 2f+1 个节点对区块 B 投了票,由于总节点数为 3f+1,所以这两部分节点的交集为 (2f+1)*2 - (3f+1) = f+1,其中错误节点数为 f,所以交集一定有一个正确节点,这个节点对区块 A 和区块 B 都投了票,这与行为 2 产生了矛盾,所以假设不成立。

可见 2f+1 既是我们为了保证活性只能收集的最大数量,同时也是投票的最小数量(为了保证交集至少有一个正确节点),这个投票对应的节点集合称为 Quorum(委员会),投票集合称为 Quorum Certificate(委员会证书,简称 QC)。正如我们上面分析的,QC 具有一个非常重要的性质:任何两个 Quorum 至少有一个共同的正确节点。我们把这个性质称为 QC 性质。因为一个 Quorum 的节点数量为 2f+1,而错误节点数为 f,因此 Quorum 中至少有 f+1 个正确节点,所以 QC 性质也可以表述成 任何两个 f+1 个正确节点的集合至少有一个共同节点。关于 QC 性质的更多讨论,可以参考我的另一篇文章:深入理解PBFT算法——提交阶段的作用

1.5 活性

上文我们讨论了安全性,接下来我们重点关注下活性。

视图切换

共识算法活性丢失的最直接来源是 leader 出错。当 leader 为错误节点时(宕机或发送任意消息等),可能完全不发提案,也可能给其他节点发送任意不同的提案,使得每个节点都无法收集够 2f+1 个正确投票,共识无法正常进行。所以当检测到 leader 为错误节点时,需要更换 leader,我们称 leader 的一个任期为视图(view),更换 leader 的过程为 “视图切换”,每个视图有一个唯一的编号,称为视图号,并且每次视图切换时视图号都递增 1。至此,提案除了高度和区块之外,还多了一个视图号。

那么如何检测 leader 出错呢?最简单的办法是设定超时时间,如果超过某个时间还没有对某个高度的提

  • 7
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值