不可靠网络
不可靠网络
分布式系统是无共享的系统,即每台机器都有自己的内存和磁盘,一台机器不能访问另一台机器的内存或磁盘,只能通过网络向服务器发出请求,网络是这些机器可以通信的唯一途径。这些机器也就是网络中的节点,网络将节点联接起来,但是网络也带来了一系列的问题。网络消息的传播有先后,消息丢失和延迟是经常发生的事情。
典型的网络模式有如下三种:同步网络(节点同步执行,消息延迟有限,高效全局锁
- 请求可能已经丢失(可能有人拔掉了网线
) 。 - 请求可能正在排队,稍后将交付(也许网络或收件人超载
) 。 - 远程节点可能已经失效(可能是崩溃或关机
) 。 - 远程节点可能暂时停止了响应(可能会遇到长时间的垃圾回收暂停
) ,但稍后会再次响应。 - 远程节点可能已经处理了请求,但是网络上的响应已经丢失(可能是网络交换机配置错误
) 。 - 远程节点可能已经处理了请求,但是响应已经被延迟,并且稍后将被传递(可能是网络或者你自己的机器过载
) 。

发送者甚至不能分辨数据包是否被发送:唯一的选择是让接收者发送响应消息,这可能会丢失或延迟。这些问题在异步网络中难以区分:您所拥有的唯一信息是,您尚未收到响应。如果您向另一个节点发送请求并且没有收到响应,则无法说明原因。处理这个问题的通常方法是超时(Timeout
真实世界的网络故障
有一些系统的研究和大量的轶事证据表明,即使在像一家公司运营的数据中心那样的受控环境中,网络问题也可能出乎意料地普遍。在一家中型数据中心进行的一项研究发现,每个月大约有
诸如
当网络的一部分由于网络故障而被切断时,有时称为网络分区(network partition)或网络断裂(netsplit
如果网络故障的错误处理没有定义与测试,武断地讲,各种错误可能都会发生:例如,即使网络恢复。,集群可能会发生死锁,永久无法为请求提供服务,甚至可能会删除所有的数据。。如果软件被置于意料之外的情况下,它可能会做出出乎意料的事情。处理网络故障并不意味着容忍它们:如果你的网络通常是相当可靠的,一个有效的方法可能是当你的网络遇到问题时,简单地向用户显示一条错误信息。但是,您确实需要知道您的软件如何应对网络问题,并确保系统能够从中恢复。有意识地触发网络问题并测试系统响应
故障检测
许多系统需要自动检测故障节点。例如:
- 负载平衡器需要停止向已死亡的节点转发请求(即从移出轮询列表(out of rotation
) ) 。 - 在单主复制功能的分布式数据库中,如果主库失效,则需要将从库之一升级为新主库。
不幸的是,网络的不确定性使得很难判断一个节点是否工作。在某些特定的情况下,您可能会收到一些反馈信息,明确告诉您某些事情没有成功:
-
如果你可以到达运行节点的机器,但没有进程正在侦听目标端口(例如,因为进程崩溃
) ,操作系统将通过发送FIN 或RST 来关闭并重用TCP 连接。但是,如果节点在处理请求时发生崩溃,则无法知道远程节点实际处理了多少数据。 -
如果节点进程崩溃(或被管理员杀死
) ,但节点的操作系统仍在运行,则脚本可以通知其他节点有关该崩溃的信息,以便另一个节点可以快速接管,而无需等待超时到期。例如,HBase 做这个。 -
如果您有权访问数据中心网络交换机的管理界面,则可以查询它们以检测硬件级别的链路故障(例如,远程机器是否关闭电源
) 。如果您通过互联网连接,或者如果您处于共享数据中心而无法访问交换机,或者由于网络问题而无法访问管理界面,则排除此选项。 -
如果路由器确认您尝试连接的
IP 地址不可用,则可能会使用ICMP 目标不可达数据包回复您。但是,路由器不具备神奇的故障检测能力——它受到与网络其他参与者相同的限制。
关于远程节点关闭的快速反馈很有用,但是你不能指望它。即使
合理的超时等待
如果超时是检测故障的唯一可靠方法,那么超时应该等待多久?不幸的是没有简单的答案。长时间的超时意味着长时间等待,直到一个节点被宣告死亡(在这段时间内,用户可能不得不等待,或者看到错误信息
当一个节点被宣告死亡时,它的职责需要转移到其他节点,这会给其他节点和网络带来额外的负担。如果系统已经处于高负荷状态,则过早宣告节点死亡会使问题更严重。尤其是可能发生,节点实际上并没有死亡,而是由于过载导致响应缓慢;将其负载转移到其他节点可能会导致级联失效(cascading failure
设想一个虚构的系统,其网络可以保证数据包的最大延迟——每个数据包要么在一段时间内传送,要么丢失,但是传递永远不会比
不幸的是,我们所使用的大多数系统都没有这些保证:异步网络具有无限的延迟(即尽可能快地传送数据包,但数据包到达可能需要的时间没有上限
网络拥塞和排队
在驾驶汽车时,由于交通拥堵,道路交通网络的通行时间往往不尽相同。同样,计算机网络上数据包延迟的可变性通常是由于排队:
- 如果多个不同的节点同时尝试将数据包发送到同一目的地,则网络交换机必须将它们排队并将它们逐个送入目标网络链路。繁忙的网络链路上,数据包可能需要等待一段时间才能获得一个插槽(这称为网络连接
) 。如果传入的数据太多,交换机队列填满,数据包将被丢弃,因此需要重新发送数据包- 即使网络运行良好。

-
当数据包到达目标机器时,如果所有
CPU 内核当前都处于繁忙状态,则来自网络的传入请求将被操作系统排队,直到应用程序准备好处理它为止。根据机器上的负载,这可能需要一段任意的时间。 -
在虚拟化环境中,正在运行的操作系统经常暂停几十毫秒,而另一个虚拟机使用
CPU 内核。在这段时间内,虚拟机不能从网络中消耗任何数据,所以传入的数据被虚拟机监视器。排队(缓冲) ,进一步增加了网络延迟的可变性。 -
TCP 执行流量控制(flow control) (也称为拥塞避免(congestion avoidance)或背压(backpressure) ) ,其中节点限制自己的发送速率以避免网络链路或接收节点过载。。这意味着在数据甚至进入网络之前,在发送者处需要进行额外的排队。
而且,如果
在公共云和多租户数据中心中,资源被许多客户共享:网络链接和交换机,甚至每个机器的网卡和
在这种环境下,您只能通过实验方式选择超时:测量延长的网络往返时间和多台机器的分布,以确定延迟的预期可变性。然后,考虑到应用程序的特性,可以确定故障检测延迟与过早超时风险之间的适当折衷。更好的一种做法是,系统不是使用配置的常量超时时间,而是连续测量响应时间及其变化(抖动
TCP 与UDP
一些对延迟敏感的应用程序(如视频会议和
在延迟数据毫无价值的情况下,