《三国杀》是一款热门的卡牌游戏,结合中国三国时期背景,以身份为线索,以卡牌为形式,益智休闲,老小皆宜。
东汉末年,袁绍做为盟主,汇合了十八路诸侯一块儿攻打董卓。算法
在讲解以前,咱们先聊下分布式协议和算法总体脉络。小程序
如今不少开发同窗对分布式的组件怎么使用都有必定经验,也知道 CAP
理论和 BASE
理论的大体含义。但认真去看分布式算法的真的不多,缘由有三
:架构
我会在后续的文章中用故事、大白话的方式来说解分布式算法的原理,以及学习路线究竟是怎么样的。分布式
学习分布式协议和算法的路线能够是先学习四大基础理论,做为地基,再学习分布式协议和算法,就像是在地基上建房子。地基打好了,才能建更稳固的高楼大厦。学习
因篇幅缘由,本篇只涉及拜占庭将军问题。区块链
你们可能听过拜占庭将军问题。它是由莱斯利·兰伯特提出的点对点通讯中的基本问题,spa
拜占庭
位于现在的土耳其的伊斯坦布尔
,是东罗马帝国
的首都。因为当时拜占庭罗马帝国国土辽阔,为了达到防护目的,每一个军队都分隔很远,将军与将军之间只能靠信差传消息。在战争的时候,拜占庭军队内全部将军和副官必须达成一致的共识,决定是否有赢的机会才去攻打敌人的阵营。可是,在军队内有可能存有叛徒和敌军的间谍,这个就是拜占庭容错问题。设计
实际上拜占庭问题是分布式领域最复杂的一个容错模型,一旦理解它,就能掌握分布式共识问题的解决思路,还能帮助你们理解经常使用的共识算法,也能够帮助咱们在工做中选择合适的算法,或者设计合适的算法。code
为何第一个基础理论是拜占庭将军问题?教程
由于它很好地抽象出了分布式系统面临的共识问题。
上面提到的 8 种分布式算法中有 5 种跟拜占庭问题相关,能够说弄懂拜占庭问题对后面学习其余算法就会容易不少。
下面我用三国杀游戏中的身份牌来说解拜占庭将军问题。
三国杀中主要有四种身份:主公、忠臣、反贼、内奸。每一个游戏玩家都会得到一个身份牌。主公只有 1 个。忠臣 最多 2 个,反贼最多 4个,内奸最多一个。
主公身份牌
获胜条件: 消灭全部反贼和内奸
技巧: 以本身生存为首要目标,分散反贼注意力。配合忠内剿灭反贼并判断谁是忠谁是内。
忠臣身份牌
获胜条件:保护主公存活的前提下消灭全部反贼和内奸。
技巧:忠臣是主公的屏障,威慑反贼和内奸的天平。
反贼身份牌
获胜条件:消灭主公便可获胜。
技巧: 反贼做为数量最多的身份,须要集中火力猛攻敌人弱点。正确的思路是获胜的关键。
内奸身份牌
获胜条件: 先消灭反贼和忠臣,最后与主公单挑成为最后惟一辈子还者。
技巧:正确的战术+ 冷静的头脑+ 运气。
东汉末年,袁绍做为盟主,汇合了十八路诸侯一块儿攻打董卓。把董卓定为反贼,袁绍定为主公,另外有两个忠臣和一个内奸,就选这三个风云人物:曹操,刘备,孙坚(孙权的爸比),内奸扮演的角色是忠臣,主公和两个忠臣不知道内奸的身份,都看成忠臣对待了。
董卓是很是强大的,拥有精良的西凉兵,麾下还有战神吕布。你们都知道三英站吕布的故事,吕布以一已之力对阵刘备、张飞、关羽三人。
要想干掉董卓,袁绍必须统一忠臣的做战计划,三位忠臣还不知道有什么其余花花肠子,有一个仍是内奸。若是内奸暗通反贼董卓,给忠臣发送误导性的做战信息,该怎么办?另外假定这几个忠臣都是经过书信交流做战信息,若是书信被拦截了或书信里面的信息被替换了咋办?这些场景均可能扰乱做战计划,最后出现有的忠臣在进攻,有的忠臣撤退了。那么反贼就能够乘此机会发起进攻,逐一攻破。
袁绍原本就没有曹操的机智,那他如何让忠臣们达成共识,制定统一的做战计划呢?
上面的映射关系就是一个拜占庭将军问题的一个简化表述,袁绍如今面临的就是典型的共识问题。也就是在可能有误导信息的状况下,采用合适的通信机制,让多个将军达成共识,制定一致性的做战计划。
刘备、曹操、孙坚经过信使传递进攻或撤退的信息,而后进行协商,究竟是进攻仍是撤退。遵循少数服从多数,不容许弃权。
曹操疑心比较重,侦查了反贼的地形后,决定撤退。而刘备和孙坚定定进攻。
一方选择撤退
曹操收到的信息:进攻 2 票,本身的一张撤退票,票数一比,进攻票:撤退票 = 2 : 1,按照上面的少数服从多数原则进行投票表决,曹操仍是会进攻。那么三方的做战方案都是进攻,因此是一个一致性的做战方案。最后打败了董卓。
由于咱们前期的设定,孙坚做为内奸,早已与反贼董卓私下沟通好了,不攻打董卓。
内奸登场-撤退
刘备收到进攻和撤退各一票,而本身又选择撤退,因此刘备获得的票数是:进攻 : 撤退 = 1 : 2,听从少数服从多数的原则,刘备选择最后选择撤退,那么三方的做战方案都是撤退,因此也是一个一致性的做战方案。
内奸看了上述计划,发现忠臣都撤退了,并无被消灭,就想经过使诈的方式来消灭其中一个忠臣。
内奸使诈-一进一退
那么结果是什么呢?
刘备的票数为进攻 2 票,撤退 1 票,曹操的票数为进攻 1 票,撤退 2 票。按照少数服从多数的原则,刘备最后会选择进攻,而曹操会选择撤退,孙坚做为内奸确定不会进攻,刘备单独进攻反贼董卓,势单力薄,被董卓干掉了。
从这个场景中,咱们看到内奸孙坚经过发送误导信息,很是容易地就干扰了刘备和曹操的做战计划,致使两位忠臣被逐一击破。这个现象就是二忠一判难题。那么主公袁绍该怎么解决这个问题?
就是将袁绍也参与进来进行投票,这样就增长了一位忠臣的数量。三个忠臣一个叛贼。而后 4 位将军作了一个约定,若是没有收到命令,则执行默认命令,好比撤退。另外约定流程来发送做战信息和如何执行做战指令。这个解法的关键点就是执行两轮做战信息协商。
咱们来看下第一轮是怎么作的。
咱们用图来演示:袁绍做为主公先发送做战信息,做战指令为进攻。而后曹操、刘备、孙坚收到进攻的做战指令。
第一轮
再来看下第二轮是怎么作的。
若是孙坚使诈,好比给曹操和刘备都发送撤退信息,以下图所示。那么刘备和曹操收到的做战信息为 进攻 2票,撤退 1 票,按照少数服从多数的原则,最后刘备和曹操执行进攻,实现了做战计划的一致性,曹操和刘备联合做战击败了反贼董卓(即便孙坚没有参加做战。)
孙坚使诈 - 两撤退
假如孙坚使诈,给曹操发送撤退指令,给刘备发送进攻指令,那么刘备收到的做战信息是进攻 3票,确定会发起进攻了,而曹操收到的做战信息是进攻 2 票,撤退 1 票,最后曹操仍是会进攻,因此刘备和曹操仍是联合做战击败了反贼董卓。
如此看来,引入了一位指挥官后,确实能够避免孙坚使诈,但若是是孙坚在第一轮做为指挥官,其余人做为副官呢?
孙坚使诈 - 一进一退
第一轮孙坚向其中一个副官袁绍发送撤退指令,向另外两个副官曹操、刘备发送进攻指令。那么第一轮的结果以下图:
第一轮
第二轮孙坚休息,其余副官按照孙坚发送的指令开始向另外的副官发送指令。
以下图所示,最后曹操、刘备、袁绍收到的指令为进攻 2 票,撤退 1 票,按照少数服从多数原则,三我的都是发起进攻。执行了一致的做战计划,保证做战的胜利。
第二轮
经过上面的演示,咱们知道了如何解决拜占庭将军问题。其实兰伯特在他的论文中也提到过如何解决。
若是叛将人数为 m,将军数 n >= 3m + 1,那么就能够解决拜占庭将军问题。前提条件:叛将数 m 已知,须要进行 m + 1 轮的做战协商。
这个公式,你们只须要记住就能够了,推到过程能够参考论文。
好比上述的攻打董卓问题,曹操、刘备、孙坚三我的当中,孙坚是叛将,他可使诈,使做战计划不统一。必须增长一位忠臣袁绍来协商共识,才能达成一致性做战计划。
那能够在不增长忠臣的状况下,解决拜占庭的二忠一判问题呢?
解法二就是经过签名消息。好比将军之间经过印章、虎符等信物进行通讯。来保证这几个特征:
限于篇幅缘由,签名的演示这里就不作展开了,感兴趣的@我,后续会加上。
经过三国杀角色来说解分布式中共识场景。那他们和分布式系统的映射关系是怎么样的呢?
可不要小瞧拜占庭问题,它但是分布式场景最复杂的的故障场景。好比在数字货币的区块链技术中就有用到这些知识点。并且必须使用拜占庭容错算法(也就是 Byzantine Fault Tolerance,BFT
)。
拜占庭容错算法还有 FBFT
算法,PoW
算法,固然不会在这篇中去讲这些算法,后续再讲解。一口吃不了大胖子~
有了拜占庭容错算法,确定有非拜占庭容错算法,顾名思义,就是没有发送误导信息的节点。CFT
算法就是解决分布式系统中存在故障,但不存在恶意节点的场景下的共识问题。简单来讲就是可能因系统故障形成丢失消息或消息重复,但不存在错误消息、伪造消息。对应的算法有 Paxos
算法、Raft
算法、ZAB
协议。后续讲解~
上面提到了 5 种算法,竟然都是跟拜占庭问题有关,你说今天讲的拜占庭问题重要不重要?
这么多算法该如何选择?
节点可信,选非拜占庭容错算法。不然就用拜占庭容错算法,如区块链中用到的 PoW 算法。
巨人的肩膀:分布式协议与算法,极客时间
建了学习交流群,能够扫码加我,备注[加群] 一块儿进阶!
我是悟空,努力变强,变身超级赛亚人!
我是悟空,努力变强,变身超级赛亚人!手写了一套 Spring Cloud 进阶教程和 PMP 刷题小程序。 欢迎关注公众号:悟空聊架构