「分布式系列」拜占庭将军问题

简介: 拜占庭将军问题介绍

拜占庭概述


首先来说说,什么是拜占庭


网络异常,图片无法展示
|


拜占庭即拜占庭帝国,又称东罗马帝国,首都位于如今土耳其的伊斯坦布尔。如上图可以看到,当时的拜占庭帝国国土辽阔,横跨亚、欧、非大陆,环抱地中海。


拜占庭将军问题


网络异常,图片无法展示
|

在那个冷兵器时代,为了征服与反征服,在如此辽阔的疆域不同地方经常驻守着由成百上千个将军领导的军队,如上图。


  • 拜占庭帝国的军队要面临的现实问题是,如何在广阔的疆域内实现所有军队的统一调度、消息交互。在那个冷兵器时代,消息指令的传递只能依靠通信士兵人为进行传递。
  • 而因此正由于是人为传递消息,若通信士兵在传递途中因暴病、天气、地理等各种原因没有及时传递消息,再或者进行了叛变,故意不将消息传递或将统一发号的命令进行虚假篡改,那么将军们得到的指令会大相径庭,行动得不到统一保证,因此传递消息的信道是不可靠的,因此导致出现行动执行的一致性问题。


综上,便是拜占庭将军问题


拜占庭将军问题,实质上是一致性问题,是不同个体(将军)之间在分布式环境(辽阔疆域)中通过不可靠信道(通信士兵)接收消息(命令)后采取一致性行动的问题。


分布式领域中“拜占庭将军问题”


网络异常,图片无法展示
|


拜占庭将军问题,其实是一个现实存在的共性问题,只要场景和条件成立便可以认为它是某个领域的拜占庭将军问题,是一个广泛问题的现实子集而已。


我们把这个问题延伸到计算机和互联网领域的话,分布式已经是互联网中常见的服务部署方案,由于硬件错误、网络拥塞或断开以及遭到恶意攻击,计算机和网络可能出现不可预料的行为,这和拜占庭将军问题产生场景和条件是相仿的。


据此,莱斯利·兰伯特(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


https://www.jianshu.com/p/81aadcea109b

相关文章
|
算法 区块链
理解分布式一致性:拜占庭容错与PBFT
理解分布式一致性:拜占庭容错与PBFT
理解分布式一致性:拜占庭容错与PBFT
|
1月前
|
NoSQL Java Redis
太惨痛: Redis 分布式锁 5个大坑,又大又深, 如何才能 避开 ?
Redis分布式锁在高并发场景下是重要的技术手段,但其实现过程中常遇到五大深坑:**原子性问题**、**连接耗尽问题**、**锁过期问题**、**锁失效问题**以及**锁分段问题**。这些问题不仅影响系统的稳定性和性能,还可能导致数据不一致。尼恩在实际项目中总结了这些坑,并提供了详细的解决方案,包括使用Lua脚本保证原子性、设置合理的锁过期时间和使用看门狗机制、以及通过锁分段提升性能。这些经验和技巧对面试和实际开发都有很大帮助,值得深入学习和实践。
太惨痛: Redis 分布式锁 5个大坑,又大又深, 如何才能 避开 ?
|
3月前
|
NoSQL Redis
基于Redis的高可用分布式锁——RedLock
这篇文章介绍了基于Redis的高可用分布式锁RedLock的概念、工作流程、获取和释放锁的方法,以及RedLock相比单机锁在高可用性上的优势,同时指出了其在某些特殊场景下的不足,并提到了ZooKeeper作为另一种实现分布式锁的方案。
112 2
基于Redis的高可用分布式锁——RedLock
|
3月前
|
缓存 NoSQL Java
SpringBoot整合Redis、以及缓存穿透、缓存雪崩、缓存击穿的理解分布式情况下如何添加分布式锁 【续篇】
这篇文章是关于如何在SpringBoot应用中整合Redis并处理分布式场景下的缓存问题,包括缓存穿透、缓存雪崩和缓存击穿。文章详细讨论了在分布式情况下如何添加分布式锁来解决缓存击穿问题,提供了加锁和解锁的实现过程,并展示了使用JMeter进行压力测试来验证锁机制有效性的方法。
SpringBoot整合Redis、以及缓存穿透、缓存雪崩、缓存击穿的理解分布式情况下如何添加分布式锁 【续篇】
|
11天前
|
NoSQL Redis
Redis分布式锁如何实现 ?
Redis分布式锁通过SETNX指令实现,确保仅在键不存在时设置值。此机制用于控制多个线程对共享资源的访问,避免并发冲突。然而,实际应用中需解决死锁、锁超时、归一化、可重入及阻塞等问题,以确保系统的稳定性和可靠性。解决方案包括设置锁超时、引入Watch Dog机制、使用ThreadLocal绑定加解锁操作、实现计数器支持可重入锁以及采用自旋锁思想处理阻塞请求。
47 16
|
1月前
|
缓存 NoSQL Java
大数据-50 Redis 分布式锁 乐观锁 Watch SETNX Lua Redisson分布式锁 Java实现分布式锁
大数据-50 Redis 分布式锁 乐观锁 Watch SETNX Lua Redisson分布式锁 Java实现分布式锁
61 3
大数据-50 Redis 分布式锁 乐观锁 Watch SETNX Lua Redisson分布式锁 Java实现分布式锁
|
1月前
|
NoSQL Redis 数据库
计数器 分布式锁 redis实现
【10月更文挑战第5天】
48 1
|
1月前
|
NoSQL 算法 关系型数据库
Redis分布式锁
【10月更文挑战第1天】分布式锁用于在多进程环境中保护共享资源,防止并发冲突。通常借助外部系统如Redis或Zookeeper实现。通过`SETNX`命令加锁,并设置过期时间防止死锁。为避免误删他人锁,加锁时附带唯一标识,解锁前验证。面对锁提前过期的问题,可使用守护线程自动续期。在Redis集群中,需考虑主从同步延迟导致的锁丢失问题,Redlock算法可提高锁的可靠性。
75 4

热门文章

最新文章