本系列为学习极客时间的 《分布式协议与算法实战》
拜占庭将军问题:有叛徒的情况下,如何才能达成共识?
共识难题
如何在可能有误导信息的情况下,采用合适的通讯机制,让多个将军达成共识,制定一致性的作战计划?
假设只有 3 个国家要攻打秦国,这三个国家的三位将军,咱们简单点儿,分别叫齐、楚、燕。同时,又因为秦国很强大,所以只有半数以上的将军参与进攻,才能击败敌人(注意,这里是假设哈,你别较真),在这个期间,将军们彼此之间需要通过信使传递消息,然后协商一致之后,才能在同一时间点发动进。
二忠一叛的难题
现在按照少数服从多数的原则进行投票,整个集体按照多数票的结果进行行动。
问题1 错误情报
本来
在 齐 和 燕 看来,撤退 :进攻 = 1 :1
此时
无论楚投哪一个,都是2: 1 ,也就是整个集体是共同撤退或者进攻
但如果
向齐发送了“撤退”,向燕发送了“进攻”
燕看到的是,撤退:进攻 =1:2
齐看到的是,撤退:进攻 =2:1
此时现燕单独进攻秦军,当然,最后肯定是因为寡不敌众,被秦军给灭了。
问题1解决方法一 口信消息型
首先,三位将军都分拨一部分军队,由苏秦率领,苏秦参与作战计划讨论并执行作战指令。这样,3 位将军的作战讨论,就变为了 4 位将军的作战讨论,这能够增加讨论中忠诚将军的数量。
然后呢,4 位将军还约定了,如果没有收到命令,就执行预设的默认命令,比如“撤退”。除此之外,还约定一些流程来发送作战信息、执行作战指令,比如,进行两轮作战信息协商。
第一轮:
先发送作战信息的将军作为指挥官,其他的将军作为副官;指挥官将他的作战信息发送给每位副官;
每位副官,将从指挥官处收到的作战信息,作为他的作战指令;如果没有收到作战信息,将把默认的“撤退”作为作战指令。
第二轮:
除了第一轮的指挥官外,剩余的 3 位将军将分别作为指挥官,向另外 2 位将军发送作战
信息;然后,这 3 位将军按照“少数服从多数”,执行收到的作战指令。
情况一:忠诚将军先开始发布信息
设苏秦先发起作战信息,作战指令是“进攻”。那么在第一轮作战信息协商中,苏秦向齐、楚、燕发送作战指令“进攻”
此时
齐: 进攻
楚: 进攻
燕: 进攻
第二轮中,齐、楚、燕分别作为指挥官,向另外 2 位发送作战信息“进攻”,因为楚已经叛变了,所以,为了干扰作战计划,他就对着干,发送“撤退”作战指令。
此时:
齐: 进攻、进攻、撤退
楚: 进攻、进攻、进攻
燕: 进攻、进攻、撤退
按照原则,齐和燕与苏秦一起执行作战指令“进攻”,实现了作战计划的一致性,保证了作战的胜利
情况二:背叛的将军先开始发布信息
在第一轮作战信息协商中,楚向苏秦发送作战指令“进攻”,向齐、燕发送作战指令“撤退”。
苏齐: 进攻
齐: 撤退
燕: 撤退
在第二轮作战信息协商中,苏秦、齐、燕分别作为指挥官,向另外两位发送作战信息。
苏齐: 进攻、撤退、撤退
齐: 撤退、进攻、撤退
燕:撤退、进攻、撤退
按照原则,苏秦、齐和楚一起执行作战指令“撤退”,实现了作战计划的一致性。也就是说,无论叛将楚如何捣乱,苏秦、齐和燕,都执行一致的作战计划,保证作战的胜利。
这个解决办法,其实是兰伯特在论文《The Byzantine Generals Problem》中提到的口信消息型拜占庭问题之解:
如果叛将人数为 m,将军人数不能少于 3m + 1 ,那么拜占庭将军问题就能解决了。
算法的前提是,m是已知的,即能够容忍的叛徒数。
n 位将军,最多能容忍 (n - 1) / 3 位叛将
问题1解决方法二 签名消息型
在不增加将军人数的时候,直接解决二忠一叛的问题
实现一个签名(信物):
- 忠诚将军的签名无法伪造,而且对他签名消息的内容进行任何更改都会被发现
- 任何人都能验证将军签名的真伪
情况一:忠诚将军先开始发布信息
设齐先发起作战信息,作战指令是“进攻”
一旦叛将小楚修改或伪造收到的作战信息,那么燕在接收到楚的作战信息的时候,会发现齐的作战信息被修改,楚已叛变,这时他执行齐发送的作战信息。
此时 齐和燕会一起行动,达成了要求。
情况二:叛徒将军先开始发布信息
设 楚先发布不同的信息给齐、燕。那么在后面的通信过程中就会发现楚给不同的国家发了不同的指令。则知道楚国叛变,然后商量新的决策。
而通过签名机制约束叛将的叛变行为,任何叛变行为都会被发现,也就会实现无论有多少忠诚的将军和多少叛将,忠诚的将军们总能达成一致的作战计划。
总结
故事里的各位将军,可以理解为计算机节点;
忠诚的将军,可以理解为正常运行的计算机节点;
叛变的将军,可以理解为出现故障并会发送误导信息的计算机节点;
信使被杀,可以理解为通讯故障、信息丢失;
信使被间谍替换,可以理解为通讯被中间人攻击,攻击者在恶意伪造信息和劫持通讯
二忠一叛问题
三个节点,其中一个节点下线或者出现其他故障,无法正常提供服务,
如何确保整个集体的决策正确问题