分布式高可用算法
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

1.4.3 链路失败

链路失败是设计分布式算法正确性的第三大挑战,主要表现在以下方面。

第一,窃听。当消息在链路上传递时,如果经历了基于广播的网络(例如以太网),或者经过了其他的中间设备,那么消息可能被分布式系统以外的第三方实体获得,从而造成信息泄露。不过,这种信息泄露并不影响分布式系统的正确运行。

第二,篡改。当消息在链路上传递时,如果被第三方获得了,那么第三方可以对该消息加以篡改后再次将其发送到链路上,从而使一些正确的进程在收到了第三方发出的伪造消息后,执行了本不应该执行的步骤,最终导致分布式系统失败。此时,进程仍然是正确的,因为它依然严格遵守预设的算法执行步骤,但由于链路的失败而造成了分布式系统的失败。

第三,丢失。当消息在链路上传递时,有可能被丢失。例如,当消息经由以太网进行传递时,恰逢某一台以太网交换机重启,在重启的某个瞬间就可能存在消息丢失的情况。

第四,乱序。当消息在链路上传递时,可能存在先发后至或者后发先至的情况。例如,在一个IP网络中,进程A向进程B先后发出了两个消息,分别为M1和M2,由于IP网络中的任意两点可以存在多条路由,因此有可能先发出的消息M1经历了一条距离较远、延迟较大的路由,而后发出的消息M2经历了一条距离较近、延迟较小的路由,从而导致先发的M1晚于后发的M2到达目的地进程B。

第五,重发。当消息在链路上传递时,同一个消息有可能被重复传递两次或以上次数。例如,在一个IP网络中,有一个消息M本应该经由网络设备A、B、C……向目标进程发送。由于这些网络设备均采用“存储-转发”模式进行消息转发,因此存在这么一个时刻:B刚把消息向C转发出去后(这时B也不知道C是否收到了消息),正准备向A发送确认报文时,B宕机了(或者B与A之间的物理链路断开了),因此A没有收到B的确认报文,于是A就选择另一条不同于“A->B->C”的路由(例如“A->D->C”路由)转发消息M。而实际上,消息M已经被B转发到了C,因此C将两次收到消息M,一次是来自B,另一次是来自D。

有人认为,对于上述丢失、乱序、重发问题,都可以采用TCP/IP协议解决。在很多对性能要求不苛刻的工程实践中,也的确采用TCP/IP协议避免了丢失、乱序和重发问题。但是分布式算法本身并不要求像 TCP/IP 协议那样严格遵守“先进先出”(First In First Out,FIFO)原则。实际上,在一个分布式系统中,由于多个进程并发执行,消息的接收进程本来就不对消息发送的先后顺序做假定,因此像TCP/IP协议这样强FIFO的链路其实是过于严格了。不过,再强调一下,绝大多数工程应用对性能的要求并未苛刻到TCP/IP协议难以满足的地步,相反,使用标准成熟的TCP/IP协议能够大幅节省工程开发时间,因此在实际应用中,TCP/IP 协议仍然不失为一种实用的选择。

此外,链路失败的复杂性并不仅体现在以上五点上,还体现在它与进程失败之间的关系上。比如,进程A向进程B发送一个心跳请求,但没有得到应有的回应,这既可能是因为进程B遇到了崩溃式失败,也可能是因为A和B之间的链路遇到了丢包。进程和进程之间除通过链路以外没有其他的通信手段,而链路也不可靠,那么一个进程凭什么知道另一个进程是正确还是失败呢?本书后面会介绍同步异步部分同步三个模型来讨论这些问题。

综上所述,并发执行、进程失败、链路失败三大挑战使设计分布式算法非常复杂。Lamport 之所以在 2013 年获得图灵奖,是因为他从看似极度混乱的分布式现象中找到了内在联系,并建立了定义清晰、良好的模型,为人们学习、研究和利用分布式系统打下了坚实的理论基础。