不可靠的网络

举报
JavaEdge 发表于 2022/07/30 23:46:06 2022/07/30
【摘要】 我们只关注分布式无共享系统,即通过网络连接的一堆机器。网络是跨节点通信的唯一途径,假设每台机器都有自己的内存和磁盘,一台机器不能直接访问另一台机器的内存或磁盘。无共享并非构建系统的唯一方式,但它已经成为构建互联网服务的主要方式,其原因如下:相对便宜,因为它不需要特殊的硬件,可以利用商品化的云计算服务,通过跨多个地理分布的数据中心进行冗余可以实现高可靠性。互联网和数据中心(通常是以太网)中的大...

我们只关注分布式无共享系统,即通过网络连接的一堆机器。网络是跨节点通信的唯一途径,假设每台机器都有自己的内存和磁盘,一台机器不能直接访问另一台机器的内存或磁盘。

无共享并非构建系统的唯一方式,但它已经成为构建互联网服务的主要方式,其原因如下:相对便宜,因为它不需要特殊的硬件,可以利用商品化的云计算服务,通过跨多个地理分布的数据中心进行冗余可以实现高可靠性。

互联网和数据中心(通常是以太网)中的大多数内部网络都是异步分组网络(asynchronous packet networks),一个节点能向另一个节点发送消息(数据包),但网络不保证何时到达或者是否能到达。若你发送请求后并等待响应,很多事情可能出错(如图-1):

  1. 请求可能已经丢失(可能有人拔了网线)
  2. 请求可能在某队列中排队,无法马上发送(也许网络或接收方已过载)
  3. 远程节点可能已失效(如崩溃或关机)
  4. 远程节点可能暂无法响应(如长时间STW)
  5. 远程节点已完成请求处理,但响应已丢失(如网络交换机配置错误)
  6. 远程接收节点已完成请求处理,但响应被延迟,并且稍后将被传递(如网络或你自己的机器过载)

图-1:若发送请求并未得到响应,则无法区分(a)请求是否丢失,(b)远程节点是否关闭或(c)响应是否丢失

发送者甚至不能分辨数据包是否完成发送,只能让接收者回复响应消息,但回复可能丢失或延迟。这些问题在异步网络很难区分,发送者拥有的唯一信息是,尚未收到响应,无法判断具体原因。

处理该问题通常采用超时:等待一段时间后,若仍未收到回复,则放弃,并认为响应不会到达。但即使判定超时,仍不清楚远程节点是否收到请求(一种情况,请求仍在某地排队,即使发送者放弃了 ,但最终请求会发送到接收者)。

2.1 现实的网络故障

网络分区

当网络的一部分由于网络故障而被切断时,有时称为 网络分区(network partition)网络断裂(netsplit)。我使用更一般的术语 网络故障(network fault),以免与存储系统的分区(分片)混淆。

即使网络故障在你的环境中非常罕见,故障可能发生的事实,意味着你的软件需要能够处理它们。无论何时通过网络进行通信,都可能会失败,这是无法避免的。

若网络故障的错误处理没有处理或测试,可能有惊喜。如即使网络恢复,集群可能死锁,永久无法提供服务,甚至误删所有数据。

处理网络故障并不意味总需复杂容错措施:假定网络很可靠,故障时的简单方法是向用户提示错误信息。但前提是确实需知道你的软件如何应对网络问题,以确保系统最终能恢复。

2.2 故障检测

许多系统需自动检测故障节点,如:

  • 负载均衡器需避免向已失效节点继续转发请求(将其下线)
  • 对主从复制的分布式DB,若主库失效,需将某从库升级为新主库

但网络的不确定性很难判断一个节点是否确实失效。某些特定情况下,可能收到一些反馈信息,明确告诉你某些事不成功:

  • 若可登录到节点,但发现服务进程没有监听目标端口(如因为进程崩溃),os将通过发送 FIN 或 RST 标志的数据包,来辅助关闭并重用 TCP 连接。但若节点在处理请求时崩溃,则无法知道远程节点实际处理了多少数据
  • 若服务进程崩溃(或被管理员杀死),但节点os仍正常运行,可通过脚本通知其他节点,以便新节点快速接管,而无需等待超时到期。HBase就是这样
  • 若能访问IDC网络交换机的管理界面,则可通过管理接口查询是否存在硬件级别链路故障(如远程节点是否掉电)。但局限性是,若通过互联网连接或处于共享IDC而无法访问交换机或由于网络问题根本无法登录管理界面,则排除此选项
  • 若路由器已确认你尝试连接的 IP 地址不可访问,则会返回 ICMP 目标不可达数据包回复请求。但路由器不具备故障检测能力,它和网络其他节点并无本质区别

远程节点关闭的快速反馈很有用,但不能指望。即使TCP确认已经传送了一个数据包,应用程序在处理前可能已崩溃。若想确保一个请求是否成功,需应用程序级别的正确响应。

总之,若故障,你可能会在堆栈的某层得到错误响应,但最好假设你根本得不到任何回应。接着重试(TCP重试是透明的,但也可在应用级别重试),等待超时后,若还没收到响应,则最终声明节点已失效。

2.3 超时和无限期的延迟

若超时是检测故障的唯一方法,则超时应等待多久?没有标准答案:

  • 较长超时值意味着长时等待,才宣告节点死亡(期间,用户只能等待或看到错误信息)
  • 较短超时可更快检测到故障,但可能误判一个节点失效,而实际只是暂时性能波动(如由于节点或网络上的负载峰值)。过早声明一个节点已死会有问题,若该节点实际上是活着的,并正在执行一些动作(如发送一封邮件),而新节点接管了,则该动作可能执行两次

当一个节点被宣告失效,其职责需转移到其他节点,这会给其他节点和网络带来额外负担。尤其是若此时系统已处于高负荷状态,若节点实际上没死亡,只是由于过载导致其响应缓慢,这时将其负载转移到其他节点可能会导致级联失效,极端的会服务雪崩。

设想某虚拟系统,其网络能保证数据包最大延迟在一定范围内:每个数据包要么在一段时间d内完成交付,要么丢失。假设非故障节点总在一段时间r内完成处理一个请求。能保证每个成功请求在 2 d + r 2d + r 内收到响应,若在此时间内没收到响应,则知道网络或远程节点失效,则 2 d + r 2d + r 是个合理超时设置。

可惜大多系统都没类似保证:异步网络理论上无限的延迟,且多数服务端也不保证在给定时间内完成处理请求。若超时时间很短,往返时间只需要一个短暂的网络延迟尖峰就会导致包超时,进而将系统标记为失效。

2.3.1 网络拥塞和排队

驾车时由于交通拥堵,导致通行时间变化很大。同理,计算机网络的数据包延迟的可变性一般也是由于排队:

  • 当多个不同节点同时尝试将数据包发送到同一目的地,网络交换机会将它们排队并依次将数据包转发到目标网络,如图-2。若网络负载过大,数据包可能等待一段时间才能获得发送机会(即网络拥塞)。若传入数据太多,交换机队列满了,之后的数据包将被丢弃,导致大量数据包重传
  • 当数据包到达目标机器,若所有CPU核都繁忙,则网络的数据包传入请求将被os排队,直到应用程序能处理。根据机器的配置和负载,这可能引入一段不确定的等待时间
  • 虚拟化环境中,正在运行的os经常暂停几十ms,因为另一个虚拟机正在使用CPU核。这段时间,VM不能从网络中接收任何数据,所以传入的数据包被VM监视器排队缓冲,进一步增加网络延迟的不确定性
  • TCP执行流量控制(也叫拥塞消除,congestion avoidance,或背压backpressure),节点会主动限制自己的发送速率,避免加重网络链路或接收节点的负载。这意味着数据甚至在进入网络前,已在发送者处就得排队

图-2:多节点同时将流量发送到同一目标,则其交换机队列可能被填满。端口1、2和 4都试图发送数据包到端口3

且若TCP在某超时范围内没收到确认,则认为数据包已丢失而触发自动重传。尽管应用程序没看到数据包丢失和重新传输这一过程,但它看到延迟(等待超时到期,然后等待重新传输的数据包得到确认)。

TCP与UDP

一些对延迟敏感的应用程序,如视频会议和 IP 语音(VoIP),使用UDP而非TCP。这是可靠性和可变性之间的折衷:UDP不支持流量控制也不重传丢失的数据包,因此可避免网络延迟不确定的因素(但它仍受切换队列和调度延迟影响)。

若延迟或丢弃的数据毫无价值,UDP才是选择。如VoIP电话呼叫中,可能没有足够的时间重新发送丢失的数据包,并在扬声器上播放数据。在这种情况下,重发数据包没有意义 —— 应用程序必须使用静音填充丢失数据包的时隙(导致声音短暂中断),然后在数据流中继续。重试发生在人类层:way,你能再说一遍吗?

所有这些因素都会造成网络延迟的变化或不确定性:

  • 拥有足够备用容量的系统可以轻松排空队列
  • 高负载系统,很快就能积累很长队列

在公共云和多租户IDC中,资源被许多客户共享:网络链接和交换机,甚至每个机器的网卡和 CPU(在虚拟机上运行时)。批处理工作负载(如MapReduce)很容易使网络带宽饱和。通常用户无法控制或了解其他客户对共享资源的使用情况,若附近某人正在使用大量资源,则网络延迟可能会发生剧变。

这时只能通过实验一步步设置超时:在一段较长时期内、先在多台机器多次测量网络往返时间,以确定延迟的预期范围。然后结合应用特点,在故障检测和过早超时风险之间选个合适的折衷值。

更推荐做法,超时设置并非一个常量,而是持续测量响应时间及其变化(抖动),然后根据最新响应时间分布自动调整。可用 Phi Accrual 故障检测器完成,目前在Akka和Cassandra中使用。TCP重传超时也采用类似机制。

2.4 同步网络与异步网络

若网络层能在规定延迟内完成数据包的发送,而不会丢弃数据包,则分布式系统就简单多了。为何不在硬件层面上解决该问题,使网络可靠,然后软件就不必担心呢?

为回答该问题,可将IDC网络和传统的固定电话网络(非移动蜂窝,非 VoIP)比较:语音延迟和掉话罕见。一个电话需要一个很低的端到端延迟,以及足够的带宽来传输你声音的音频采样数据。在计算机网络中有类似的可靠性和可预测性不是很好吗?

当通过电话网络拨电话时,会建立一个电路:在两个呼叫者之间的整个路线上为呼叫分配一个固定的,有保证的带宽量,这个电路会保持至通话结束。这种网络是同步:即使数据经过多个路由器,也不会受到排队影响,因为呼叫的 16 位空间已经在网络的下一跳中保留。而且由于没有排队,网络的最大端到端延迟是固定的。称为有界延迟。

2.4.1 网络延迟可预测吗?

电话网络中的电路与 TCP 连接不同:电路是固定数量的预留带宽,在电路建立时没有其他人能用,而 TCP 连接的数据包会尝试所有可用的网络带宽。TCP可传送任意大小可变的数据块(如电子邮件或一个网页),它会尽可能在最短时间内传输它。 TCP连接空闲时,不占用任何带宽 [^ii]。

[^ii]: 除了偶尔的 keepalive 数据包,若TCP keepalive 被启用。

若IDC网络和互联网是电路交换网络,那么在建立电路时就可建立一个受保证的最大往返时间。但它们并不是:以太网和 IP 是 分组交换协议,不得不忍受排队及其导致的网络不确定延迟。这些协议全无电路的概念。

为何数据中心网络和互联网使用分组交换?它们针对突发流量进行了优化。电路适用于音频或视频通话,在通话期间需每秒传送固定数量比特。但请求网页,发送电子邮件或传输文件无特定带宽要求,只是希望尽快完成。

若想通过电路传输文件,得预测一个带宽分配:

  • 太低,传输速度太慢,导致网络容量闲置
  • 太高,电路就无法建立(因为如果无法保证其带宽分配,网络不能建立电路)

因此,将电路用于突发数据传输会浪费网络容量,并且使传输不必要地缓慢。相比之下,TCP动态调整数据传输速率,以适应所有可用的网络容量。

但目前在多租户数据中心和公共云或通过互联网 [^iv] 进行通信时,此类服务质量尚未启用。当前部署的技术不允许我们对网络的延迟或可靠性作出任何保证:我们必须假设网络拥塞,排队和无限的延迟总是会发生。因此,超时时间不存在绝对 “正确” 的值,需通过实验确定。

[^iv]: 互联网服务提供商之间的对等协议和通过 BGP 网关协议(BGP) 建立的路由,与 IP 协议相比,更接近于电路交换。在这个级别上,可以购买专用带宽。但是,互联网路由在网络级别运行,而不是主机之间的单独连接,而且运行时间要长得多。

延迟和资源利用率

更一般地,可将延迟的变化视为动态资源分区的结果。

假设两台电话交换机之间有一条线路,可同时进行 10,000 个呼叫。通过此线路切换的每个电路都占用其中一个呼叫插槽。因此,你可以将线路视为可由多达 10,000 个并发用户共享的资源。资源以静态方式分配:即使你现在是线路上唯一的呼叫,并且所有其他 9,999 个插槽都未使用,你的电路仍将分配与线路充分利用时相同的固定数量的带宽。

而互联网是动态分享网络带宽。发送者互相竞争,以让他们的数据包尽快通过网络,网络交换机也是动态决定发送哪个数据包(即带宽分配)。这种方法有排队的缺点,但优点是最大限度地利用带宽。线路固定成本,所以若你充分利用,则通过线路发送的每个字节都会成本更低。

CPU类似:如多个线程间动态共享CPU核,则一个线程有时必须在os的运行队列里等待,而另一个线程正在运行,这样每个线程都有可能被暂停一个不定时间。但和为每个线程分配固定CPU周期相比,会更好地利用硬件,这也是使用 VM 的重要动机。

若资源静态分配(如专用硬件和专用带宽分配),则某些环境中可实现延迟的确定性。但这是以降低利用率为代价。而动态资源分配的多租户提供更好利用率,所以它更便宜,但引入可变延迟的缺点。

网络的可变延迟不是一种自然规律,而只是成本 / 收益权衡结果。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。