拜占庭概述
首先来说说,什么是拜占庭?
拜占庭即拜占庭帝国,又称东罗马帝国,首都位于如今土耳其的伊斯坦布尔。如上图可以看到,当时的拜占庭帝国国土辽阔,横跨亚、欧、非大陆,环抱地中海。
拜占庭将军问题
在那个冷兵器时代,为了征服与反征服,在如此辽阔的疆域不同地方经常驻守着由成百上千个将军领导的军队,如上图。
- 拜占庭帝国的军队要面临的现实问题是,如何在广阔的疆域内实现所有军队的统一调度、消息交互。在那个冷兵器时代,消息指令的传递只能依靠通信士兵人为进行传递。
- 而因此正由于是人为传递消息,若通信士兵在传递途中因暴病、天气、地理等各种原因没有及时传递消息,再或者进行了叛变,故意不将消息传递或将统一发号的命令进行虚假篡改,那么将军们得到的指令会大相径庭,行动得不到统一保证,因此传递消息的信道是不可靠的,因此导致出现行动执行的一致性问题。
综上,便是拜占庭将军问题。
拜占庭将军问题,实质上是一致性问题,是不同个体(将军)之间在分布式环境(辽阔疆域)中通过不可靠信道(通信士兵)接收消息(命令)后采取一致性行动的问题。
分布式领域中“拜占庭将军问题”
拜占庭将军问题,其实是一个现实存在的共性问题,只要场景和条件成立便可以认为它是某个领域的拜占庭将军问题,是一个广泛问题的现实子集而已。
我们把这个问题延伸到计算机和互联网领域的话,分布式已经是互联网中常见的服务部署方案,由于硬件错误、网络拥塞或断开以及遭到恶意攻击,计算机和网络可能出现不可预料的行为,这和拜占庭将军问题产生场景和条件是相仿的。
据此,莱斯利·兰伯特(Leslie Lamport)
等提出了著名的拜占庭将军问题(Byzantine Failures) 来论述分布式环境下点对点通信时在存在消息丢失的不可靠信道上试图通过消息传递的方式达到一致性是较为困难的。
莱斯利·兰伯特(Leslie Lamport)
也是著名的Paxos
一致性算法的作者,关于本系列分布式介绍后续的Raft
一致性算法也是在改进Paxos
的初衷进行设计的,这里简单了解下概念相关性线索轨迹,感兴趣可以继续阅读本篇后续文章。
这里将现实场景的拜占庭帝国和分布式服务做下对比,如下:
场景 |
信源 |
信道 |
消息 |
不可靠原因 |
拜占庭帝国 |
中央 <----> 将军 |
通信士兵 |
命令 |
天气、地理、战争、叛变 |
分布式服务 |
服务节点 <----> 服务节点 |
网络 |
报文 |
损毁、超时、中断、恶意攻击 |
问题核心剖析
问题核心
分布式环境/服务中拜占庭将军问题要解决的核心问题是:如何在缺少可信任的中央节点和可信任的通道的情况下,分布在网络中的各个节点应如何达成共识的一致性问题。 这是分布式服务中首要解决的议题,它也是其他所有问题的基础和根本保证。
问题分析
这里尝试剖析问题本质需要从现象到本质一层层剖析根源,这里个人认为是首先有 分布式环境 的客观现实导致服务集群的 节点分散 ,当我们充分利用和享受分布式带来的优势后也需要面临和解决海量节点个体统一协调、指挥的 一致性问题 ,而无论是让统一的控制中心下发指令还是让节点之间互相协商都必须经历 消息交互 才能实现通信彼此了解对方和外部环境的最新状态信息,而承载交互的可能的最小承载因子是 信息 ,因此我们试着从根源开始剖析!
根据克劳德·艾尔伍德·香农(Claude Elwood Shannon)
提出的信息论,我们一般将信息分为信源、信宿、信道
三部分,信息体
作为载体通过信道
穿梭在信源
与信宿
之间。
下面我们基于以上概念将其引申到分布式环境下,每个服务节点在发送消息时便是信源角色,若是接收消息则是信宿角色,信道是建立在节点之前双向的通道。
构成 |
角色定位 |
作用 |
可能存在问题 |
信源 |
通信发起者 |
产生信息体 |
无法溯源、异常 |
信宿 |
通信接收者 |
接收信息体 |
伪造、异常 |
信道 |
通信通道 |
传递信息体 |
被劫持、被监听、中断 |
信息体 |
通信载体 |
装载信息体 |
篡改、丢失 |
因此,我们剖析该问题呈现特点是节点不可靠性、通道不可靠性、信息不可靠性,因此要针对这些问题特点来进行针对性解决,从而确保一致性的达成。
问题解决
解决方案:口头协议
实现过程
口头协议 ,又称为 口信消息(Oral message) 。满足以下三个条件的方式称为 口头协议 :
- 每个被发送的消息都能够被正确的投递(信道绝对可信)
- 信息接收者知道是谁发送的消息(消息来源可知,但不知道上一个消息来源,即不可溯源)
- 能够知道缺少的消息
该方案的实现方式是:
- [STEP-1] 各个节点接收Commander指令Command-1
- [STEP-2] 每个节点收到Commander消息后,再将该消息分发到其他节点上,最终每个节点都会收到其他节点发来的消息集合
{Commander消息、其他节点传递的Commander消息}
,根据消息集合来判断下一步如何执行。
节点 |
收到的消息集合 |
A |
{ CommandCommander发送、CommandB传递、CommandC传递 } |
B |
{ CommandCommander发送、CommandA传递、CommandC传递 } |
C |
{ CommandCommander发送、CommandA传递、CommandB传递 } |
不可靠场景
Commander不可靠
当 Commander 不可靠时,各节点收到信息集合为
节点 |
收到的消息集合 |
决策判断 |
节点执行结果 |
分布式一致性 |
A |
{ command-0Commander发送、command-1B传递、command-1C传递 } |
指令不一致 |
不执行 |
一致 |
B |
{ command-1Commander发送、 command-0A传递、command-1C传递 } |
指令不一致 |
不执行 |
一致 |
C |
{ command-1Commander发送、 command-0A传递、command-1B传递 } |
指令不一致 |
不执行 |
一致 |
Node不可靠
少数不可靠
少数节点不可靠场景 ,当 A 不可靠时,各节点收到信息集合为
节点 |
收到的消息集合 |
决策判断 |
节点执行结果 |
分布式一致性 |
A |
{ command-1Commander发送、command-1B传递、command-1C传递 } |
不可靠节点 |
执行伪造命令command-0 |
多数一致 |
B |
{ command-1Commander发送、 command-0A传递、command-1C传递 } |
指令不一致 |
不执行 |
多数一致 |
C |
{ command-1Commander发送、 command-0A传递、command-1B传递 } |
指令不一致 |
不执行 |
多数一致 |
多数不可靠
多数节点不可靠场景 ,当 A、C 不可靠时,各节点收到信息集合为
节点 |
收到的消息集合 |
决策判断 |
节点执行结果 |
分布式一致性 |
A |
{ command-1Commander发送、command-1B传递、command-0C传递 } |
不可靠节点 |
执行伪造命令command-0 |
|
B |
{ command-1Commander发送、 command-0A传递、command-0C传递 } |
指令不一致 |
不执行 |
|
C |
{ command-1Commander发送、 command-0A传递、command-1B传递 } |
不可靠节点 |
执行伪造命令command-0 |
|
综上,我们可以看到,无论是发号施令的Commander,还是执行命令的Node节点,当不可靠节点数量较多时,分布式中的一致性将遭受破坏,无法保证。
确保一致性情况下,不可靠节点与总结点数量关系
若n
代表所有节点(含Commander、Node)总数,m
代表不可靠节点数量,则他们必须满足n≧3m+1
这样的数量关系方可保证分布式的一致性,感兴趣可以自己推导下,以下是样例:
节点总数(n) |
Commander数量(1) |
Node数量(n-1) |
不可靠最大节点数(m) |
4 |
1 |
3 |
1 |
7 |
1 |
6 |
2 |
10 |
1 |
9 |
3 |
... |
... |
... |
... |
不足
- 消息无法溯源,无法确定其他节点传递消息的正确性
- 当不可靠节点大多数存在的情况下,无法达成一致性
解决方案:书面协议
为了进一步解决口头协议的不足,改进点如下:
- 为了确保其他节点传递消息的正确性可溯源,让节点通信都增加签名信息
- 当不可靠节点大多数存在时无法达成一致性,但这是一个未知数,无法实现按照推演公式安排节点总数量来保证容错,而消息传递加签名信息的方式能很好的确保消息传递的可溯源、准确性,以此可以解决任意不可靠节点存在的场景
实现过程
书面协议 ,又称为 签名协议 。该方案的实现方式是:
- [STEP-1] 各个节点接收Commander带有签名的指令Command-1
- [STEP-2] 每个节点收到Commander消息后,将该消息进行签名后再分发到其他节点上,最终每个节点都会收到其他节点发来的带有签名信息的消息集合
{Commander签名消息、其他节点签名的Commander消息}
,根据消息集合来判断下一步如何执行。
节点 |
收到的消息集合(均带有签名信息) |
A |
{ CommandCommander签名、CommandB签名、CommandC签名 } |
B |
{ CommandCommander签名、CommandA签名、CommandC签名 } |
C |
{ CommandCommander签名、CommandA签名、CommandB签名 } |
特点
基于口头协议的特点,签名协议规定,每条消息只可以复制,然后加上自己的签名再发给其他节点,增加如下特点:
- [1] 节点签名是不能伪造的,内容修改可检测
- [2] 任何节点都可以识别Commander的签名,不可靠节点可以伪造Commander的签名
不足
- 尽管消息传递均被签名,但是发送者不一定可信,有可能是A节点使用了C节点签名来通知B节点,因此需要一个中心化的签名管理规则或机构对各个发送者进行核验方可确认真实性
书面协议的本质就是引入了签名机制,这使得所有消息都可追本溯源。化解了口头协议中1/3要求,只要采用了书面协议,可靠节点就可以达到一致。
解决方案:工作量证明
工作量证明算法(PoW算法,Proof of Work) 广泛应用于存在恶意攻击和篡改且不可靠的分布式环境下,应该广泛的是区块链技术。
中本聪
在比特币白皮书中,通过比特币协议给出了终极解决方案如下:
- 引入工作量证明机制,只有第一个完成规定计算工作的节点才能传播信息,从而保证一段时间内只有一个提案。
- 引入非对称加密算法,为信息传递提供签名技术支持,以保证消息传递的私密性,且不可抵赖、不可篡改。
关于该部分方案的实现在后续章节中单独论述。
拜占庭将军问题是由莱斯利·兰伯特(Leslie Lamport)
等提出的,但真正解决这一难题的是中本聪
。兰伯特
提出的Paxos算法
,还有后续改进的Raft算法、Zab协议
都是基于可靠信道环境下消息不会被篡改和伪造等恶意攻击的前提下实现的分布式一致性协议,面对不可靠信道等存在恶意篡改风险的分布式环境是无法保证一致性的。
总结
拜占庭将军问题,不关心结果的对与错,只关心节点执行的一致性问题。
现有的 分布式一致性协议和算法 主要可分为两类:
- 非拜占庭容错算法
即非容错算法(Crash Fault Tolerance, CFT),解决的是分布式系统中存在故障,但不存在恶意攻击的场景下的共识问题。也就是说,在该场景下可能存在消息丢失,消息重复,但不存在消息被篡改或伪造的场景。一般用于局域网场景下的分布式系统,如分布式数据库。属于此类的常见算法有Paxos算法、Raft算法,、Zab协议等。 - 拜占庭容错算法
可以解决分布式系统中既存在故障,又存在恶意攻击场景下的共识问题。一般用于互联网场景下的分布式系统,如在数字货币的区块链技术中。属于此类的常见算法有PBFT算法、PoW算法。
参考
https://baike.baidu.com/item/拜占庭将军问题/265656 拜占庭问题
https://baike.baidu.com/item/信息论/302185 信息论
https://zhuanlan.zhihu.com/p/44024734
https://www.cnblogs.com/aspirant/p/13321203.html
https://www.cnblogs.com/aspirant/p/13321816.html
https://www.8btc.com/article/70370