尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

拜占庭容错共识核心:EIG树原理与消息复杂度解析

拜占庭容错共识核心:EIG树原理与消息复杂度解析 这篇论文笔记我拖了很久才动笔。原因很简单《Reaching agreement in the presence of faults》这篇论文虽然发表于1980年但它的影响力远远超出了那个时代今天分布式系统领域几乎所有关于容错共识的讨论最后都可以追溯到这篇论文和它的姊妹篇《The Byzantine Generals Problem》。而EIGExponential Information Gathering这个缩写正是理解这篇论文核心思想的一把钥匙。第一次读这篇论文的时候我其实相当困惑。EIG这个名字在原文里根本找不到它更多出现在后来的教材和课程里作为一种把口头消息算法OM算法形式化的精炼表达。但恰恰是这种形式化表达把论文里递归、树形结构、消息传递路径这些概念串成了一个完整的体系。这篇笔记我想换一个角度来写不按论文的原始结构逐段翻译而是以EIG树为线索把问题定义、算法设计、容错界限、复杂度分析这条逻辑链完整地捋一遍顺便把我踩过的理解和实现上的坑一并记录下来。1. 这篇论文到底在解决什么问题1.1 拜占庭将军问题的场景定义要理解EIG先得把问题本身说清楚。论文开篇描述的场景是一组将军分别率领军队围攻一座城市他们必须就进攻还是撤退达成一致否则就会战败。问题是将军之间只能通过信使传递消息而其中一些将军可能是叛徒他们会故意发送误导性消息来破坏共识。这个比喻翻译成分布式系统的语言就是系统中有n个节点其中最多有m个节点是故障的——这里说的故障不是简单的宕机而是拜占庭故障也就是说故障节点可以任意行为包括发送错误消息、选择性不发送消息、对不同节点发送不同消息等等甚至这些节点可能已经被攻击者完全控制。论文要解决的问题是在这样的条件下所有正常节点能否就某个值达成一致且这个值必须满足一定的正确性要求。这里有两个关键的正确性条件。第一是终止性Termination所有正常节点最终都必须做出决定第二是一致性Agreement所有正常节点的决定必须相同。但还有第三个条件经常被忽略——有效性Validity如果所有正常节点初始持有相同的值v那么它们最终决定的也必须是v。有效性条件保证了共识结果不是随便选一个值而是和系统的初始状态合理关联。这三个条件缺一不可少了任意一个共识问题就失去了意义。论文的一个伟大之处在于它把这个问题抽象到了一个极度简洁的程度。它不关心消息内容的具体含义不关心节点处理消息的速度差异只关心一个纯粹的、关于消息传递和决策规则的逻辑问题。这种抽象能力在今天的论文里已经很难见到了今天很多论文上来就是一堆工程细节反而是这种直击本质的风格更值得学习。1.2 同步假设EIG协议成立的前提这里必须花点篇幅讲同步假设因为这是整个协议成立的地基也是很多人在理解时最容易忽略的地方。EIG协议以及OM算法都假设系统是同步的消息的传递时间存在一个已知的上界节点的处理速度也存在一个已知的上界所有节点基本可以认为是步调一致地执行协议。这个假设为什么至关重要因为EIG协议的核心机制是分层传播和逐层决策每一轮的消息交换都有严格的时序依赖。如果系统是异步的也就是消息可能无限期延迟那么没有任何确定性算法能够同时满足终止性、一致性和有效性——这是FLP不可能性定理的内容虽然那篇论文发表于1985年但根源上的限制是客观存在的。EIG之所以能在同步假设下工作正是因为它依赖一个明确的轮次结构每一轮中节点知道自己在第几轮知道这一轮该向谁发送消息、接收谁的消息。用生活化的类比来说同步系统就像军训队列教官喊向左转所有人必须在规定时间内完成动作教官知道每个人是否完成了。异步系统则像微信群聊你发了一条消息但你完全不知道其他人什么时候能看到、会不会回复。在群聊这种环境下如果有人故意捣乱你根本无法区分他是真的没看到还是假装没看到。这就是为什么EIG必须要同步假设也是为什么很多实践系统比如区块链的某些共识机制会通过超时机制、轮次同步等手段把实际环境模拟成同步系统来使用EIG这类协议。2. EIG的核心思路用树把消息历史记录下来2.1 从OM算法到EIG树论文原文描述的是OM算法Oral Message算法它的工作方式是这样的第一轮指挥官司令向所有副官发送自己的值接下来每一轮收到消息的节点把自己收到的值转发给其他所有节点这个过程持续m1轮最后所有节点根据收集到的信息进行多数投票。OM算法用递归来定义描述起来很优雅但理解起来始终隔了一层。EIG树则是把OM算法的运行过程用树形结构显式地表达出来这也是EIG名字的来源——指数式信息收集因为树的节点数量随轮数呈指数增长。我第一次看到EIG树的时候OM算法的那些递归细节一下子就有了画面感。EIG树的构建规则非常直接。根节点是每个节点自己的初始值。第一轮结束后每个节点知道了所有其他节点的初始值于是在树的第二层为每个其他节点建立一个子节点子节点的值就是那个节点声称的初始值。第二轮开始后每个节点把自己在第一轮收到的全部信息转发出去同时接收其他所有节点转发过来的信息这些信息形成树的第三层。这里的关键之处在于路径的约束消息传递路径上不能出现重复节点。也就是说树的每一层对应消息传递路径上的一个节点而这条路径上的节点不能重复出现。原因也很直白如果一条消息经过了某个节点两次那么第二次经过时该节点已经知道了这条消息的内容这不会增加任何新的信息量却会让树变得无限膨胀。对于n个节点、m个叛徒的情况EIG树的深度是m1层。根节点在第0层第1层有n-1个节点第2层有(n-1)(n-2)个节点以此类推第k层有(n-1)(n-2)...(n-k)个节点。整个树的规模是O(n^(m1))。这个指数级的规模是EIG协议最显著的代价后面我们会专门讨论这个问题的后果。2.2 EIG树为什么能挡住叛徒EIG树之所以能够达成共识根源在于它保留了一条消息从源头到当前节点所经过的完整路径。假设节点j收到了一条来自节点i的消息声称的内容是v那么EIG树中记录的不只是节点i说了v而是存在一条路径i - ... - j在这条路径上传递的值是v。这意味着什么它意味着j可以对同一个源头的信息进行交叉验证。如果节点i是正常节点那么无论它通过多少条不同路径向j传递信息内容都应该是一致的。如果节点i是叛徒它对不同路径上的消息施加了篡改那么j最终会在EIG树中看到同一个源头对应着多个不同的值——这些值虽然不同但它们的传递路径不同而路径本身是消息在分布式系统中传递的指纹。决策阶段每个节点自底向上计算自己的决策。对于深度为d的节点如果d等于m1最深一层直接取该节点存储的值作为其值如果d小于m1则取该节点的所有子节点值中的多数值。逐层向上最后根节点的多数值就是整个节点的最终决策值。这里有一个微妙的细节多数投票的过程中节点不是简单地统计所有子节点而是要对齐路径。举例来说对于一个深度为2的节点path(i,j)表示路径i-j上的消息它的子节点是path(i,j,k)其中k是不同于i和j的节点。投票时以j声称的、经由各条不同路径传到当前节点的值为基础取多数。这个对齐过程保证了即使某个中间节点是叛徒它的影响也会被其他正常路径的信息淹没。3. 口头消息为什么必须满足 n 3m3.1 3m1的直观论证论文最著名的结论之一就是在口头消息签名验证不可用的条件下当且仅当n 3m时问题才有解。这个界限的证明非常精巧理解它对整个协议设计的价值怎么强调都不为过。为什么n必须大于3m让我们从叛徒的视角来想。叛徒的目标是让不同正常节点做出不同的决定。由于正常节点最终通过多数投票来决定叛徒如果想成功搞破坏就必须保证在某些关键的投票环节中虚假信息能够占据多数。考虑最极端的情况m个叛徒全部集中向某个正常节点L发起攻击。L收到来自其他正常节点的n-m-1个真实消息如果本轮恰好有m个叛徒直接向它传消息那么真实消息就是n-2m-1个和最多m个虚假消息。为了让L的多数投票结果正确真实消息的数量必须严格大于虚假消息的数量。也就是说n-2m-1 m化简得到n 3m1即n 3m。这个推导是EIG协议正确性的核心所在。我在初读论文时一直有一个疑问为什么不是n 2m原因是叛徒不仅可以在本轮投票中直接注入虚假值还可以在更下层的位置影响投票结果。一个叛徒如果在上层靠近根节点的一层是某个正常节点的父节点它可以直接篡改该正常节点的信息。为了抵消这种影响正常节点的数量不仅要超过叛徒数量还要在多层投票中存在足够的信息冗余。n 3m正是这种冗余的最低要求。从更直观的角度理解EIG协议相当于在每一层都进行一次董事会投票而叛徒可以在每一层投出m票反对。为了保证最终结果不被颠覆正常节点必须至少占2/3以上的多数。这个2/3多数的直觉后来反复出现在各种拜占庭容错协议中比如PBFT根源就在这里。3.2 消息复杂度的代价理解了n 3m的必要性再来算算消息复杂度你会对指数信息收集这个名字有更直观的感受。假设n 3m1最小配置EIG树的总节点数为第0层1个节点根第1层n-1 3m个节点第2层(n-1)(n-2) 3m(3m-1)个节点第k层(n-1)(n-2)...(n-k)个节点总节点数大约是(3m)^(m1)量级。即使m310个节点其中3个叛徒EIG树的节点数也高达(9)^4 6561个。当m516个节点这个数字是(15)^6 ≈ 1139万。当m722个节点(21)^8 ≈ 3.78×10^10。更直接的消息复杂度来自消息传播过程。每轮中每个节点都向其他所有节点发送消息第k轮需要发送n(n-1)(n-2)...(n-k1)条消息。以m5、n16为例总消息数约为16×15×14×13×12×11 ≈ 576万条。这个数量对于现代网络来说勉强可以接受但当m10、n31时消息数量将达到31×30×...×21 ≈ 2.8×10^16条这对任何实际系统来说都是天文数字。这就是为什么论文另一个关键贡献被忽视了——它对带签名消息的算法SM算法的设计将消息复杂度从指数级降到了多项式级。这是下一节的重点。这里还要提一个容易被忽略的工程细节EIG树中每一层的消息内容长度也在增长。第k轮的消息不只是一个简单的值而是包含了前面k轮的所有信息历史。也就是说第k轮的一个消息内容的大小本身就是O(n^k)级别的。当我们在讨论消息复杂度时如果把这个因素也算进去实际的通信开销比单纯的消息条数还要高得多。很多论文笔记在分析EIG协议时只提消息条数不提消息内容膨胀的问题这在工程实现中是一个必须面对的现实。4. 带签名消息把指数级消息压下来的关键4.1 SM算法叛徒的造假能力被消除了论文的第二部分讨论了带签名消息Signed Message的模型。在这个模型下每个节点都有一个不可伪造的签名能力消息一旦被签名就不能被篡改任何节点都可以验证签名的有效性——这相当于现代密码学中的数字签名机制。为什么签名能大幅降低复杂度关键在于EIG协议之所以需要指数级的信息冗余根本原因是叛徒可以伪造消息。叛徒可以收到一条消息后篡改其中的内容再转发出去或者干脆伪造一条从未发生过的消息。由于所有正常节点都听信了这些伪造消息EIG需要大量冗余路径来进行交叉验证。而签名消息的出现从根源上消除了叛徒的造假能力。叛徒仍然可以不发送消息仍然可以拒绝转发但无法伪造一条消息声称来自其他节点。一旦消息被某个节点签名任何篡改都会被检测出来。带签名消息的SM算法的运行方式与OM算法有几个关键区别。首先节点的消息链中带有完整的签名链一个消息从源头到终点经过的每个节点都附上自己的签名。其次消息传递的轮数可以降为m轮递归深度少了一层因为签名的不可伪造性使得叛徒无法在最底层进行最后一击的篡改。第三最重要的一点容错界限从n 3m放宽到了n 2m1。这个放宽的意义是巨大的。在口头消息模型中你需要至少3个节点才能容忍1个叛徒在签名消息模型中只需要2个节点就能容忍1个叛徒。这表明拜占庭容错的主要困难不在于叛徒本身而在于叛徒可以撒谎且无法被识破。一旦引入签名叛徒的影响力就被大幅削减。4.2 n 2m1的直觉与风格对比为什么签名模型下只需要n 2m1直觉是这样的在任意投票环节中正常节点的票数至少是n-m个叛徒的票数最多是m个。只要n-m m即n 2m正常节点的多数票就能胜出。这里多出来的1是严格不等式的需要确保正常节点票数严格大于叛徒票数。对比两种模型下的复杂度可以看得很清楚模型容错界限轮数消息总量级消息内容是否可伪造OM口头消息n 3mm1O(n^(m1))可以SM签名消息n 2m1m1O(n^2·m)不可以SM算法的消息总量级是多项式的核心原因在于有了签名链之后节点在每一轮只需要向所有其他节点广播自己的签名链而不需要像OM算法那样保留每条路径的所有中间节点信息。每轮产生的消息数是O(n^2)每个节点向n-1个节点广播m轮下来总消息量是O(n^2·m)。相比EIG的指数级这是巨大的改进。这里还要插一句历史背景论文发表时的签名是基于公钥密码学的而公钥密码学在1980年还处于相对早期的阶段。论文作者在讨论签名模型时更多是在展示一个理论模型的分析结果而不是断言这种模型立刻可以工程实现。事实上直到PBFT等实用拜占庭容错协议在1999年出现签名模型的理论优势才真正转化为实践方案。今天我们在区块链、分布式账本中看到的各种共识算法很多都可以被视为SM算法在不同假设下的演进。5. 重读论文的工程体会与常见误解5.1 几个容易踩坑的理解误区这篇论文篇幅不长但逻辑密度极高非常容易误读。我梳理了几个常见误区这些都是我自己或身边朋友在读论文时踩过的坑。第一个误区认为EIG协议可以容忍任意数量的叛徒。事实上它的容错上限是m且要求n 3m或n 2m1一旦叛徒数量超过这个界限协议就无法保证正确性。论文中有一个经典的反例n3、m13个节点1个叛徒时口头消息模型下无法达成共识。很多初学者会用直觉去套这个例子觉得3个人投票少数服从多数不就行了但实际上叛徒可以分别对不同节点发送不同消息导致两个正常节点各自认为多数值是进攻另一个认为多数值是撤退——三方僵持不下。第二个误区把EIG协议当成可以抵抗不按轮次操作的异步协议。前面已经反复强调EIG依赖同步假设。如果把EIG用于异步环境而不加任何限制比如加入超时机制、或者引入逻辑时钟来模拟同步轮次那么理论上仍然可能失败。严格来说异步环境中的拜占庭共识需要随机化算法或部分同步假设。工程系统中那些号称使用EIG的方案通常都是通过某种同步机制把异步问题转化成了同步问题转化过程中必然引入额外假设。第三个误区认为EIG协议被现代系统普遍使用。恰恰相反EIG的指数级消息复杂度使其几乎不适用于大规模系统。它在理论分析、教学演示、以及理解共识本质方面有极高价值但工程系统几乎不会直接采用EIG协议。现代实用拜占庭容错协议PBFT、Tendermint、HotStuff等走的是另一条路将共识拆分为视图、轮次、提交阶段利用密码学技术和精心设计的通信模式把复杂度降到O(n^2)甚至O(n)级别。第四个误区把SM算法等同于现代签名共识算法。SM算法虽然引入了签名消息但其结构仍然是EIG式的树形信息收集仍然需要O(n^2·m)的消息量。现代协议做了更多优化不再让每个节点向所有其他节点广播自己的全部状态而是通过领导节点模式先让一个节点提出候选值其他节点基于自己掌握的信息验证和投票。这种优化大幅降低了通信复杂度但也带来了对领导节点行为的新假设比如它必须是诚实的或者至少不能是叛徒。5.2 EIG在现代分布式系统中的位置虽然EIG协议本身没有大规模落地但它的思想渗透到了许多现代系统的血脉里。理解EIG等于掌握了一把解读后来协议的钥匙。以PBFT为例它的prepare和commit阶段本质上就是在做层次化的信息确认。PBFT要求系统中有3f1个节点其中f个是拜占庭故障节点这个3f1的界限和EIG的n 3m如出一辙。PBFT并没有显式地构建EIG树但它的消息流中蕴含了经过足够多的独立路径验证后消息内容可信的思想。可以说整个拜占庭容错领域的基础架构都是由这篇论文搭建的。在区块链和Web3语境下EIG思想同样存在。各种BFT类共识协议可以看作是对叛徒将军问题的现代回答而这些协议的安全证明几乎都会追溯到n 3m这个基本界限。如果你读懂了EIG的含义再去看那些协议的白皮书很多看似复杂的签名验证、投票阶段划分、view-change机制本质上都是围绕着如何让正常节点的信息在叛徒干扰下仍能取得多数这个核心问题展开的。另一个值得注意的影响是EIG树的结构和现代机器学习中的决策树、信息级联理论也有微妙的呼应。EIG中消息传递路径就是信息交互的历史这一观点在今天的容错机制设计中以审计日志事件溯源等形式重新出现。系统的核心思想依然是要让一个分布式系统在不可信环境中做出可信决策必须保留足够多的交互历史来支撑决策的可验证性。5.3 我自己重读论文时的三点体会最后分享三个我在重读这篇论文时的真实体会它们超出了纯粹的技术层面。第一论文的核心贡献不在于提出了某个具体的算法而在于把容错共识这个看起来很直观的问题逼到了一个极其纯粹和严格的数学层面。它逼你厘清什么是共识一致性条件什么是正确性有效性条件什么是容错拜占庭故障模型这些概念今天已经成为分布式系统的公理但在1980年它们还没有被清晰定义过。阅读这篇论文相当于在重新经历一次从混乱到清晰的思考过程。第二EIG树这个数据结构之所以到今天还被反复提及是因为它用最简单的框架解释了为什么同步模型中指数级通信是必要的。当你看到n 3m和O(n^(m1))这两个结论时你会产生一种分布式系统的复杂度瓶颈在何处的直觉。这种直觉比记忆任何一条具体定理都更为宝贵。第三工程实现的复杂度与理论优雅之间存在着巨大的鸿沟。EIG协议在理论上无懈可击但真要部署到真实环境中还需要处理网络分区、节点超时、消息序错误、数据持久化以及如何在有物理故障的情况下维持同步假设等一系列问题。论文中抽象掉的细节往往占据工程实践的绝大多数精力。这不是说理论无用恰恰相反如果没有理论的指引工程实践很容易在错误的方向上费尽力气。如果你要动手模拟EIG协议比如写个小程序验证一下建议从m1、n4的最简单场景开始然后用m2、n7的场景做对比亲身体会一下叛徒消息如何在树中传播、多数投票如何在深层节点中发挥纠错作用。纸上得来终觉浅这套树形的信息传递结构只有真正画出来、跑起来你才会对论文里那些递归定义产生肌肉记忆般的理解。
返回列表