给朋友发了一条“明天下午3点在车站前见”的消息却迟迟没有回复,不知道对方有没有看到,心里难免不安。就算对方回了一句“好的”,你又可能会想:对方知道我收到这条回复了吗?计算机科学中有一个著名的问题,用两位将军的故事来阐释这种无休止的确认循环,这就是“两将军问题(Two Generals’ Problem)”。
简单来说,两将军问题是一个思想实验,它说明“在消息可能中途消失的通信信道上,双方永远无法完全确定彼此已就同一行动达成一致”。初学网络和分布式系统时几乎都会遇到它,它也被视为计算机通信问题中第一个被证明无法解决的问题。
本文将依次介绍两将军问题描绘的是怎样的情境、为什么无法解决、这个问题从何而来,以及现实中的技术如何应对这一局限。
确认的确认永无止境的两将军问题
两将军问题描述的是怎样的情境

这个问题从隔着一座城堡的两支军队的故事讲起。
(1)分头扎营的两支军队
两位将军各自率领的军队为了攻打同一座城堡,分别在不同的山丘上扎营。两支军队同时进攻就能攻陷城堡,但如果只有一方进攻,这支军队就会惨败。
(2)穿越危险山谷的信使
两位将军唯一的联络方式,是派信使穿过由城堡守军把守的山谷。信使随时可能被抓,派出信使的一方也无从得知信使是否已经抵达。
(3)将军们想要的确信
将军们不仅要定下进攻时间,还想确切地知道“我们双方都会在那个时间进攻”。只有有了这份确信,他们才能放心调动军队。
由此可见,两将军问题把双方试图在不可靠的通信信道上协调行动时遇到的困难,浓缩成了一个简单的场景。
为什么始终无法确信

看起来只要多来回派几次信使就能解决,但确认越多,同样的担忧只会不断重复。
(1)第一条消息的不安
即使第一位将军派出信使传达“清晨6点进攻”,由于不知道信使是否抵达,他也会因担心只有自己一方进攻而犹豫不决。
(2)没完没了的回复
如果第二位将军回信“已收到,6点进攻”,这回轮到第二位将军担心这封回信是否送达。即使第一位将军再派人确认自己收到了回信,这最后一名信使同样可能被抓。
(3)最后一名信使的悖论
无论来回多少次,发出最后一名信使的一方都无法知道他是否抵达。即使最后一名信使被抓,在发出方看来情况也完全一样,因此,如果进攻与否取决于这一名信使,就可能出现只有一方进攻的情况。由此得出结论:任何以固定次数往返确认的方法,都无法让两位将军完美地协调一致。
关键在于,确认消息和原始消息一样容易丢失。无论把确认叠加多少层,最后一层的不确定性始终存在。

两将军问题从何而来

这个问题是在计算机网络刚刚发展起来的20世纪70年代被整理出来的。
- 最早发表的论文(First Publication):1975年,E. A. Akkoyunlu、K. Ekanadham和R. V. Huber在一篇探讨网络通信设计约束的论文中,首次提出了这个问题及其无法解决的证明。该论文用相互联络的两伙帮派而非将军来描述这一情境。
- 命名者(Naming):数据库研究者吉姆·格雷(Jim Gray)在1978年一篇关于数据库操作系统的文章中,将这一问题称为“两将军悖论(Two Generals Paradox)”,此后以如今的将军故事广为人知。
- 扩展为更大的问题(Byzantine Generals Problem):1982年,莱斯利·兰波特(Leslie Lamport)、罗伯特·肖斯塔克(Robert Shostak)和马歇尔·皮斯(Marshall Pease)发表了“拜占庭将军问题”,探讨多位将军中混有叛徒的情况。两将军问题常被作为学习这一问题之前的入门内容来介绍。
现实技术如何应对这一局限

既然完美的确信不可能实现,现实中的技术选择的不是消除不确定性,而是把它降低到可以承受的程度。
(1)多次发送
如果第一位将军派出多名信使,他们全部被抓的概率就会大大降低。虽然不是确信,但足以大幅提高成功的可能性。
(2)确认与重传
互联网的基本通信协议TCP(Transmission Control Protocol)在建立连接时交换三次消息,发送数据后,如果在规定时间内没有收到对方的接收确认,就会重新发送。这种方式同样无法保证双方状态始终一致,但能建立起足以实际使用的可靠性。
(3)把沉默也当作信号
还有一种方法是事先约定:如果一段时间内没有任何联络,就视为对方已接受计划。这样既能少派信使,又能获得较高的确信度。
这些方式的共同点在于,它们追求的都不是完美,而是“足够可靠”。
两将军问题提醒我们,无论技术多么精密,都无法完全突破不可靠通信信道的局限。我们今天使用的即时通讯软件、支付系统和云服务,也都是在承认这一局限的基础上设计的。
接受完美的确信无法实现这一事实,并在此之上构筑安全保障,这正是设计可靠系统的第一步。