TCP的构建块

 高性能浏览器网络  | O'Reilly

TCP的构建块

TCP的构建块

网络101,第2章

互联网的核心是IP和TCP两种协议。IP或互联网协议是提供主机到主机的路由和寻址,TCP或传输控制协议是提供在不可靠信道上运行的可靠网络的抽象。TCP / IP通常也被称为互联网协议套件,Vint Cerf和Bob Kahn在1974年题为“分组网络通信协议”的文章中首次提出。

原来的建议(RFC 675)被修改了好几次,在1981年,TCP / IP的v4规范不是一个发布的,而是作为两个独立的RFC发布的:

  • RFC 791 - 互联网协议

  • RFC 793 - 传输控制协议

此后,TCP已经提出了一些改进措施,但核心业务并没有明显的变化。TCP快速替代以前的协议,现在是许多最流行的应用程序的首选协议:万维网,电子邮件,文件传输等等。

TCP提供了在不可靠信道上运行的可靠网络的有效抽象,隐藏了我们的应用程序中网络通信的大部分复杂性:丢失数据的重传,按顺序传送,拥塞控制和避免,数据完整性等。当您使用TCP流时,您可以确保发送的所有字节与接收到的字节相同,并且它们将以相同的顺序到达客户端。因此,TCP针对准确的交付进行了优化,而不是及时的。事实证明,在浏览器中优化网络性能时,也会带来一些挑战。

HTTP标准并不要求TCP作为唯一的传输协议。如果我们想要,我们可以通过数据报套接字(用户数据报协议或UDP)或任何我们选择的其他传输协议来传送HTTP,但实际上,互联网上的所有HTTP流量都是通过TCP传递的,因为它很多很方便它提供开箱即用的功能。

因此,了解TCP的一些核心机制是构建优化网页体验的基础知识。您可能不会直接在应用程序中使用TCP套接字,但是在应用程序层设计的选择将决定TCP和您的应用程序所在的底层网络的性能。

§TCP和IP协议的缠结历史

我们都熟悉IPv4和IPv6,但是如何发现IPv4(1,2,3,5)?IPv4中的4代表了TCP / IP协议的版本4,该协议于1981年9月发布。原始的TCP / IP提案加上两个协议,而v4草案正式将其分为两个独立的RFC。因此,IPv4中的v4是与TCP的关系的遗产:没有独立的IPv1,IPv2或IPv3协议。

当工作组在1994年开始“互联网协议下一代”(IPng)工作时,需要新的版本号,但是v5已经被分配给另一个实验协议:互联网流协议(ST)。事实证明,ST从来没有起飞,这就是为什么很少有人听说过。因此IPv6中的6个。

§三通握手

所有TCP连接以三次握手开始(图2-1)。在客户端或服务器可以交换任何应用数据之前,他们必须同意从两端开始分组序列号以及一些其他连接特定变量。出于安全考虑,序列号从双方随机挑选。

SYN

客户端选择一个随机序列号x并发送一个SYN数据包,它也可能包括附加的TCP标志和选项。

SYN ACK

服务器增加x一个,选择自己的随机序列号y,附加自己的一组标志和选项,并调度响应。

ACK

客户端一个递增,xy通过在握手中调度最后一个ACK数据包来完成握手。

图2-1。 三通握手

图2-1。三通握手

三次握手完成后,应用程序数据可以开始在客户端和服务器之间流动。客户端可以在ACK包之后立即发送数据包,服务器必须等待ACK才能发送任何数据。此启动过程适用于每个TCP连接,并对使用TCP的所有网络应用程序的性能具有重要意义:每个新连接将在任何应用程序数据传输之前具有完整的延迟时间。

例如,如果我们的客户位于纽约,服务器位于伦敦,我们正在通过光纤链路启动新的TCP连接,则三次握手将至少需要56毫秒(表1-1): 28毫秒,在一个方向传播数据包,之后它必须返回纽约。请注意,连接带宽不起作用。相反,延迟受到客户端和服务器之间的延迟的约束,而这又等于纽约和伦敦之间的传播时间。

三次握手造成的延迟使新的TCP连接创建成本高昂,这也是连接重用是通过TCP运行的任何应用程序的关键优化的重要原因之一。

§TCP快速打开

加载网页通常需要从数十种不同的主机中获取数百种资源。反过来,这可能需要浏览器建立数十个新的TCP连接,每个TCP连接都必须承担TCP握手的开销。不用说,这可能是Web浏览延迟的重要来源,特别是在较慢的移动网络上。

TCP快速打开(TFO)是一种机制,旨在通过允许SYN数据包中的数据传输来消除对新TCP连接造成的延迟损失。然而,它确实有自己的限制:对SYN数据包中的数据有效负载的最大大小有限制,只能发送某些类型的HTTP请求,并且它仅适用于重复连接,因为需要一个加密Cookie。有关TFO的功能和限制的详细讨论,请查看IETF最新的“TCP快速打开”草案。

启用TFO需要在客户机,服务器和应用程序的选择中明确支持。为获得最佳效果,请使用服务器上的Linux内核v4.1 +,兼容客户端(例如Linux或iOS9 + / OSX 10.11+),并在应用程序中启用相应的套接字标志。

根据Google进行的流量分析和网络仿真,研究人员已经表明,TFO可以将HTTP事务网络延迟降低15%,整个页面的加载时间平均降低10%以上,在某些情况下,高达40%延迟情况!

§拥塞避免与控制

1984年初,约翰·纳格尔(John Nagle)记录了一个称为“拥塞崩溃”的情况,这可能会影响网络节点之间具有不对称带宽容量的任何网络:

拥塞控制是复杂网络中公认的问题。我们已经发现,国防部互联网协议(IP),纯数据报协议和传输控制协议(TCP)(传输层协议)在一起使用时会受到由传输和数据报之间的交互引起的异常拥塞问题的影响层。特别是,IP网关容易受到我们称之为“拥塞崩溃”的现象的影响,特别是当这样的网关连接广泛不同带宽的网络时

如果往返时间超过任何主机的最大重传间隔,该主机将开始将相同数据报的越来越多的副本引入网络。网络现在很严重。最终交换节点中的所有可用缓冲区都将被满载,并且数据包必须被丢弃。传递的数据包的往返时间现在已经达到最大值。主机正在发送每个数据包多次,最终每个数据包的一些副本到达目的地。这是拥挤崩溃。

这个条件是稳定的。一旦达到饱和点,如果用于选择要丢弃的数据包的算法是公平的,则网络将继续在恶化条件下运行。

John Nagle,RFC 896

该报告的结论是,拥塞崩溃尚未成为ARPANET的一个问题,因为大多数节点具有均匀的带宽,并且骨干网具有相当大的过剩容量。然而,这些断言长期以来都不成立。1986年,随着网络数量的增加(5000+)和节点种类不断增加,整个网络中出现了一系列拥挤倒塌事件 - 在某些情况下,容量下降了1000,网络不可用。

为了解决这些问题,在TCP中实施了多种机制来管理可以在两个方向发送数据的速率:流量控制,拥塞控制和拥塞避免。

高级研究计划机构网络(ARPANET)是现代互联网和世界首个运营分组交换网络的前身。该项目于1969年正式启动,1983年TCP / IP协议取代了以前的NCP(网络控制程序)作为主要的通信协议。其余的,正如他们所说,是历史。

§流量控制

流量控制是一种机制,可以防止发送者用可能无法处理的数据压缩接收机 - 接收机可能在繁重的负载下可能正忙,或者只能愿意分配固定的缓冲区空间。为了解决这个问题,TCP连接的每一方通告(图2-2)自己的接收窗口(rwnd),它传达可用的缓冲区空间的大小来保存传入的数据。

首次建立连接时,双方通过使用系统默认设置启动其rwnd值。典型的网页将大部分数据从服务器传输到客户端,从而使客户端窗口成为可能的瓶颈。然而,如果客户端将大量数据流传输到服务器,例如在图像或视频上传的情况下,则服务器接收窗口可能成为限制因素。

如果由于任何原因,其中一方无法跟上,那么它可以向发件人发布一个较小的窗口。如果窗口达到零,则将其视为在缓冲区中的现有数据已被应用层清除之前不再发送数据的信号。该工作流在每个TCP连接的整个生命周期中继续:每个ACK数据包携带每一侧的最新rwnd值,允许双方动态调整数据流速到发送方和接收方的容量和处理速度。

图2-2。 接收窗口(rwnd)大小广告

图2-2。接收窗口(rwnd)大小广告

§窗口缩放(RFC 1323)

原始TCP规范分配了16位用于通告接收窗​​口大小,这将在发送方和接收方发布的最大值(2 16或65,535字节)上设置一个硬上限。事实证明,这种上限通常不足以获得最佳性能,特别是在呈现高带宽延迟产品的网络中; 更多关于此可以找到 带宽延迟产品

为了解决这个问题,RFC 1323被起草提供了一个“TCP窗口缩放”选项,这使我们能够将最大接收窗口大小从65,535字节提高到1 GB!在三次握手期间传送窗口缩放选项,并携带一个表示在将来的ACK中左移16位窗口大小字段的比特数的值。

今天,在所有主要平台上默认启用TCP窗口缩放。然而,中间节点,路由器和防火墙可以重写或甚至完全剥离此选项。如果与服务器或客户端的连接无法充分利用可用带宽,那么检查窗口大小的交互始终是一个很好的开始。在Linux平台上,窗口缩放设置可以通过以下命令进行检查和启用:

  • $> sysctl net.ipv4.tcp_window_scaling

  • $> sysctl -w net.ipv4.tcp_window_scaling=1

§慢启动

尽管在TCP中存在流量控制,但在20世纪80年代中后期,网络拥塞崩溃成为一个真正的问题。问题是流量控制阻止了发送方压倒接收机,但是没有任何机制阻止任何一方压倒底层网络:发送方和接收方都不知道在新连接开始时的可用带宽,因此需要一种估计它的机制,并使其速度适应网络内不断变化的状况。

为了说明一个这样的适应性的一个例子,想象你在家,并从远程服务器流式传输一个大型视频,可以让您的下行链路饱和,以提供最大的质量体验。然后,家庭网络上的另一个用户将打开一个新的连接来下载一些软件更新。突然之间,视频流的可用下行链路带宽的数量要少得多,视频服务器必须调整其数据速率 - 否则,如果以相同的速率继续运行,数据将简单地堆放在一些中间网关和数据包将被丢弃,导致网络效率低下。

1988年,Van Jacobson和Michael J. Karels记录了几种算法来解决这些问题:慢启动,拥塞避免,快速重传和快速恢复。所有这四个都很快成为TCP规范的强制性部分。实际上,广泛认为,技术合作计划的这些更新防止了80年代和90年代初的互联网崩溃,因为流量继续以指数速度增长。

要了解慢启动,最好先看看它的动作。所以,再次让我们回到位于纽约的我们的客户,试图从伦敦的服务器中检索一个文件。首先,执行三次握手,在双方握手期间,双方在ACK数据包内发布各自的接收窗口(rwnd)大小(图2-2)。一旦将最后的ACK数据包放在线上,我们就可以开始交换应用数据。

估计客户端和服务器之间的可用容量的唯一方法是通过交换数据进行测量,这正是缓慢启动的目的。首先,服务器将根据TCP连接初始化新的拥塞窗口(cwnd)变量,并将其初始值设置为保守的系统指定值(Linux上的initcwnd)。

拥塞窗口大小(cwnd)

在从客户端收到确认(ACK)之前,发件人可以在航班中拥有的数据量的发件人方限制。

cwnd变量不在发送方和接收方之间进行通告或交换 - 在这种情况下,它将是由伦敦服务器维护的私有变量。此外,引入了新的规则:客户端和服务器之间的最大数量的数据(不是确认的)是rwnd和cwnd变量的最小值。到目前为止这么好,但服务器和客户端如何确定拥塞窗口大小的最佳值?毕竟,如前面的例子所示,网络条件甚至在同一个两个网络节点之间变化不大,如果我们可以使用该算法,而不用手动调整每个连接的窗口大小,这将是巨大的。

解决方案是开始慢,并增加窗口大小,因为数据包被确认:slow-start!最初,cwnd的起始值被设置为1个网段; 1999年4月,RFC 2581将此值更新为4个细分; 最近,RFC 6928在2013年4月将价值再次增加到10个细分市场。

新TCP连接的最大飞行数据量是rwnd和cwnd值的最小值; 因此现代服务器最多可以向客户端发送十个网段,此时必须停止并等待确认。然后,对于每个接收到的ACK,慢启动算法指示服务器可以将其cwnd窗口大小增加一个段 - 对于每个ACK分组,可以发送两个新的分组。TCP连接的这个阶段通常被称为“指数增长”算法(图2-3),因为客户端和服务器正在尝试快速收敛它们之间的网络路径上的可用带宽。

图2-3。 拥塞控制和拥塞避免

图2-3。拥塞控制和拥塞避免

那么为什么我们正在为浏览器构建应用程序时记住一个重要的因素呢?那么HTTP和许多其他的应用协议通过TCP运行,无论可用带宽如何,每个TCP连接都必须经历慢启动阶段 - 我们不能立即使用链路的全部容量!

相反,我们从一个小的拥堵窗口开始,每一个往返双倍,即指数增长。因此,到达特定吞吐量目标所需的时间是客户端和服务器之间的往返时间和初始拥塞窗口大小的函数(达到大小N的cwnd大小的时间)。

时间达到cwnd大小的大小N

bc982fa3a121aff07c20b70f92845668.svg

对于缓慢启动影响的动手实例,让我们假设以下情况:

  • 客户端和服务器接收窗口:65,535字节(64 KB)

  • 初始拥塞窗口:10段(RFC 6928)

  • 往返时间:56 ms(伦敦到纽约)

尽管64 KB的接收窗口大小,新的TCP连接的吞吐量最初受到拥塞窗口的大小的限制。实际上,要达到64 KB的接收窗口限制,我们首先需要将拥塞窗口大小增加到45个段,这将需要168毫秒:

bbc4446900172ea4b345dc6c79e2932e.svg

这是三次往返(图2-4),可以在客户端和服务器之间达到64 KB的吞吐量!客户端和服务器可能能够以Mbps +数据速率传输的事实在建立新连接时无效 - 这是缓慢启动的。

上述示例使用十个网段的新(RFC 6928)值作为初始拥塞窗口。作为一个练习,重复与旧的四个细分相同的计算 - 你会看到这将增加一个额外的56毫秒的往返以上的结果!

图2-4。 拥塞窗口大小增长

图2-4。拥塞窗口大小增长

为了减少增加拥塞窗口所需的时间,我们可以减少客户端与服务器之间的往返时间 - 例如,将服务器在地理上靠近客户端。或者我们可以将初始拥塞窗口大小增加到10个段的新RFC 6928值。

缓慢启动对于大型流式下载不是一个大问题,因为客户端和服务器将在几百毫秒后达到最大窗口大小,并以接近最大速度继续传输 - 慢启动的成本相位在较大转移的寿命期内摊销。

然而,对于许多HTTP连接来说,这些连接通常很短,突发,在达到最大窗口大小之前,数据传输完成是不寻常的。因此,许多Web应用程序的性能往往受到服务器和客户端之间的往返时间的限制:慢启动限制了可用带宽吞吐量,这对小型传输的性能有不利影响。

§慢启动重启

除了调整新连接的传输速率之外,TCP还实现了一个慢启动重启(SSR)机制,它在连接已经空闲一段定义的时间后重置连接的拥塞窗口。理由很简单:当连接空闲时,网络状况可能发生变化,为了避免拥塞,窗口重置为“安全”默认。

不足为奇的是,SSR可能会对长时间的TCP连接的性能产生重大影响,这可能会在一段时间内空闲,例如由于用户不活动。因此,通常建议在服务器上禁用SSR,以帮助提高长时间的HTTP连接的性能。在Linux平台上,可以通过以下命令检查和禁用SSR设置:

  • $> sysctl net.ipv4.tcp_slow_start_after_idle

  • $> sysctl -w net.ipv4.tcp_slow_start_after_idle=0

为了说明三次握手和缓慢启动阶段对简单HTTP传输的影响,我们假设我们在纽约的客户端通过新的TCP连接从伦敦的服务器请求一个64 KB的文件(图2-5),并且具有以下连接参数:

  • 往返时间:56 ms

  • 客户端和服务器带宽:5 Mbps

  • 客户端和服务器接收窗口:65,535字节

  • 初始拥塞窗口:10段(e4d3c630db37ce2af158b869d489901b.svg

  • 服务器处理时间产生响应:40 ms

  • 没有包丢失,每包ACK,GET请求适合单个段

图2-5。 通过新的TCP连接获取文件

图2-5。通过新的TCP连接获取文件

0 ms

客户端开始与SYN数据包的TCP握手。

28 ms

服务器回复SYN-ACK并指定其rwnd大小。

56 ms

客户端确认SYN-ACK,指定其rwnd大小,并立即发送HTTP GET请求。

84 ms

服务器收到HTTP请求。

124 ms

服务器完成生成64 KB响应,并在暂停ACK之前发送10个TCP段(初始cwnd大小为10)。

152 ms

客户端每个接收10个TCP段和ACK。

180 ms

服务器为每个ACK递增cwnd,并发送20个TCP段。

208 ms

客户端每个接收20个TCP段和ACK。

236 ms

服务器为每个ACK增加其cwnd,并发送剩余的15个TCP段。

264 ms

客户端接收15个TCP段,每个ACK段。

在客户端和服务器之间以56 ms的往返时间在新的TCP连接上传输64 KB文件!相比之下,我们现在假设客户端能够重复使用相同的TCP连接(图2-6),并再次发出相同的请求。

图2-6。 通过现有TCP连接获取文件

图2-6。通过现有TCP连接获取文件

0 ms

客户端发送HTTP请求。

28 ms

服务器收到HTTP请求。

68 ms

服务器完成生成64 KB响应,但cwnd值已经大于发送文件所需的45个段; 因此它在一个突发中调度所有段。

96 ms

客户端接收所有45个段,每一个ACK。

同样的要求在同一连接上,但没有三次握手的成本和缓慢启动阶段的惩罚,现在花了96毫秒,这转化为性能提高了275%!

在这两种情况下,服务器和客户端都可以访问5 Mbps的上行带宽,在TCP连接的启动阶段没有任何影响。相反,延迟和拥塞窗口大小是限制因素。

事实上,如果我们增加往返时间,则在现有连接上发送的第一个和第二个请求之间的性能差距只会扩大; 作为一个练习,尝试一些不同的值。一旦开发了TCP拥塞控制技术的直觉,数十种优化,如keepalive,流水线和多路复用将不需要进一步的动力。

§增加TCP的初始拥塞窗口

将服务器上的初始cwnd大小增加到10个段(IW10)的新RFC 6928值是提高所有用户和通过TCP运行的所有应用程序性能的最简单方法之一。好消息是,许多操作系统已经更新了最新的内核以使用增加的值 - 检查相应的文档和发行说明。

对于Linux,IW10是2.6.39以上的所有内核的新默认值。但是,不要停在那里:升级到3.2+还可以获得其他重要更新的好处; 请参阅TCP的比例降低费率

§拥塞避免

重要的是要认识到,TCP被专门设计为使用丢包作为反馈机制来帮助调节其性能。换句话说,这不是一个问题,如果,而是何时会发生数据包丢失。慢启动使用保守窗口初始化连接,对于每个往返行程,将飞行中的数据量加倍,直到其超过接收器的流量控制窗口,系统配置的拥塞阈值(ssthresh)窗口或直到数据包丢失,此时拥塞避免算法(图2-3)接管。

拥塞避免的隐含假设是分组丢失表示网络拥塞:沿着路径的某处,我们遇到拥塞的链路或路由器,这被迫丢弃数据包,因此我们需要调整窗口以避免引起更多丢包以避免网络压倒。

一旦拥塞窗口被重置,拥塞避免规定了自己的算法,以便如何增长窗口以最小化进一步的损失。在某一时刻,将发生另一个丢包事件,并且该过程将重复一遍。如果您曾经看过TCP连接的吞吐量跟踪,并观察到其中的锯齿形图案,现在您知道为什么它看起来像这样:拥塞控制和避免算法调整拥塞窗口大小以解决丢包的问题网络。

最后,值得注意的是,改进拥塞控制和避免是学术研究和商业产品的一个活跃领域:适应不同的网络类型,不同类型的数据传输等。今天,根据您的平台,您可能会运行许多变体之一:TCP Tahoe和Reno(原始实现),TCP Vegas,TCP New Reno,TCP BIC,TCP CUBIC(Linux上默认)或复合TCP(默认为Windows)等等。然而,不管风味如何,所有拥塞控制和回避的核心性能影响。

§为TCP比例税率降低

确定从数据包丢失中恢复的最佳方式是一个非常重要的练习:如果你太过于激进,那么间歇性丢失的数据包会对整个连接的吞吐量产生很大的影响,如果你没有足够快地进行调整,那么你会诱发更多的丢包!

最初,TCP使用乘法减法和加法增加算法(AIMD):当丢包发生时,将拥塞窗口大小减半,然后将每个往返速度缓慢增加一个固定数量的窗口。然而,在许多情况下,AIMD过于保守,因此开发了新的算法。

比例速率降低(PRR)是由RFC 6937指定的新算法,其目的是提高丢包时的恢复速度。多好多了 根据Google开展的新算法的测量,它提供了与丢包连接的平均延迟3-10%的平均延迟。

PRR现在是Linux 3.2+内核中的默认拥塞避免算法 - 升级服务器的另一个好的原因!

§带宽延迟产品

TCP中的内置拥塞控制和拥塞避免机制具有另一重要的性能含义:最佳发送方和接收方窗口大小必须根据往返时间和目标数据速率而有所不同。

为了理解为什么会这样的情况,首先记住发送者和接收者之间的未确认的飞行中数据的最大数量被定义为接收(rwnd)和拥塞(cwnd)窗口大小的最小值:当前的接收窗口是在每个ACK中进行通信,基于拥塞控制和避免算法,发送方动态调整拥塞窗口。

如果发送方或接收方超过未确认数据的最大数量,则必须停止并等待另一端对某些数据包进行确认。需要等待多久?这是由两人之间的往返时间决定的!

带宽延迟产品(BDP)

产品数据链路的容量及其端到端的延迟。结果是在任何时间点可以在飞行中的未确认数据的最大数量。

如果发送方或接收方经常被迫停止并等待先前数据包的ACK,则会在数据流中产生空白(图2-7),从而限制连接的最大吞吐量。为了解决这个问题,窗口大小应该做得足够大,这样任何一方都可以继续发送数据,直到ACK从客户端返回给较早的数据包 - 没有间隙,最大吞吐量。因此,最佳窗口大小取决于往返时间!选择低窗口大小,您将限制连接吞吐量,而不管对等体之间可用或通告的带宽。

图2-7。 由于低拥塞窗口大小导致的传输差距

图2-7。由于低拥塞窗口大小导致的传输差距

那么流控制(rwnd)和拥塞控制(cwnd)窗口值需要多大?实际计算是一个简单的计算。首先,我们假设cwnd和rwnd窗口大小的最小值为16 KB,往返时间为100 ms:

2a61d2f4306aa5d7529d1855aabf1d09.svg

无论发送方和接收方之间的可用带宽如何,此TCP连接不会超过1.31 Mbps数据速率!为了实现更高的吞吐量,我们需要提高窗口大小或降低往返时间。

类似地,如果我们知道往返时间和两端的可用带宽,我们可以计算最佳窗口大小。在这种情况下,我们假设往返时间保持不变(100 ms),但发送方具有10 Mbps的可用带宽,接收机处于高吞吐量100 Mbps +链路上。假设它们之间没有网络拥塞,我们的目标是使客户端可用的10 Mbps链路饱和:

8430e1506bff95cf840315bd1d6d7365.svg

窗口大小至少为122.1 KB,以使10 Mbps链路饱和。回想一下,TCP中的最大接收窗口大小为64 KB,除非窗口缩放 - 参见窗口缩放(RFC 1323) - 存在:仔细检查您的客户端和服务器设置!

好消息是,窗口大小协商和调优由网络堆栈自动管理,并应相应调整。坏消息有时候仍然是TCP性能的限制因素。如果您曾经想过为什么您的连接以可用带宽的一小部分进行传输,即使您知道客户端和服务器都能够获得更高的速率,那么可能是由于窗口尺寸较小:饱和的对等广告低接收窗口,恶劣的网络天气和高分组丢失重置拥塞窗口,或显式流量整形,可能已被应用于限制连接的吞吐量。

§高速LAN中的带宽延迟产品

BDP是往返时间和目标数据速率的函数。因此,虽然往返时间是高传播延迟的常见瓶颈,但也可能是本地局域网的瓶颈!

为了实现1 Gbit / s的1ms往返时间,我们还需要至少122 KB的拥塞窗口。计算与我们前面看到的完全一样; 我们简单地将几个零添加到目标数据速率,并从往返延迟中删除相同数量的零。

§线头阻塞

TCP提供了在不可靠信道上运行的可靠网络的抽象,其包括基本的分组错误检查和校正,按顺序传送,丢失分组的重传以及流量控制,拥塞控制以及设计用于操作网络的拥塞避免在效率最高的地步。综合起来,这些功能使TCP成为大多数应用程序的首选传输。

然而,虽然TCP是一个受欢迎的选择,但它不是唯一的,也不一定是每一个场合的最佳选择。具体来说,一些功能,如按顺序和可靠的数据包传送,并不总是必需的,可能会引起不必要的延迟和负面的性能影响。

为了理解为什么会这样的情况,请记住每个TCP数据包放在电线上时都会携带唯一的序列号,并且数据必须按顺序传递给接收器(图2-8)。如果其中一个数据包在路由到接收器丢失,则所有后续数据包必须保留在接收器的TCP缓冲区中,直到丢失的数据包重发并到达接收器。因为这个工作是在TCP层内完成的,所以我们的应用程序没有对TCP重传或排队的数据包缓冲区的可见性,并且在能够访问数据之前必须等待完整的序列。相反,当它尝试从套接字读取数据时,它会看到传递延迟。这种效应被称为TCP线头(HOL)阻塞。

由线头阻塞所造成的延迟使我们的应用程序避免了处理数据包重新排序和重新组装,这使得我们的应用程序代码更简单。然而,这是以在分组到达时间(通常称为抖动)中引入不可预测的延迟变化的代价来实现的,这可能对应用的性能产生负面影响。

图2-8。 TCP线头阻塞

图2-8。TCP线头阻塞

此外,一些应用程序可能甚至不需要可靠的传递或按顺序传送:如果每个数据包都是独立的消息,则严格不必按顺序传送,如果每个消息都覆盖所有以前的消息,则可靠传送的要求可以被完全删除 不幸的是,TCP不提供这样的配置 - 所有数据包都按顺序排序并交付。

可以处理无序传送或分组丢失以及延迟或抖动敏感的应用程序可能更好地与备用传输(如UDP)配合使用。

§丢包OK

实际上,丢包是必要的,从TCP获得最好的性能!丢弃的数据包充当反馈机制,允许接收方和发送方调整其发送速率,以避免网络压倒,并最小化延迟; 请参阅本地路由器中的Bufferbloat。此外,一些应用程序可以容忍数据包丢失,而不会产生不利影响:音频,视频和游戏状态更新是不需要可靠或按顺序传送的应用程序数据的常见示例 - 顺便提及,这也是为什么WebRTC使用UDP作为其基础运输。

如果数据包丢失,则音频编解码器可以简单地在音频中插入小的中断,并继续处理传入的数据包。如果间隙很小,用户可能甚至不会注意到,等待丢失的数据包冒着在音频输出中引入可变暂停的风险,这将为用户带来更糟糕的体验。

同样地,如果我们正在交付游戏状态更新,那么等待一段时间描述其状态的数据包T-1,当我们已经拥有数据包的时间T通常是不必要的 - 理想情况下,我们会收到每一个更新,但为了避免游戏延迟,我们可以接受间歇性的损失,有利于较低的延迟。

§优化TCP

TCP是一种自适应协议,设计为对所有网络对等体公平,并最有效地利用底层网络。因此,优化TCP的最佳方法是调整TCP如何感知当前网络状况,并根据其下面和之上的层的类型和要求来调整其行为:无线网络可能需要不同的拥塞算法,并且一些应用可能需要定制服务质量(QoS)语义来提供最佳体验。

不同应用需求的紧密相互作用以及每个TCP算法中的许多旋钮使TCP调优和优化成为学术和商业研究的无穷无尽的领域。在本章中,我们仅仅描绘了管理TCP性能的许多因素。理解,分析和调整等附加机制,例如选择性确认(SACK),延迟确认和快速重传等等,使得每个TCP会话变得更加复杂(或者有趣的,取决于您的观点)。

话虽如此,虽然每个算法和反馈机制的具体细节将不断发展,但核心原则及其含义仍然保持不变:

  • TCP三次握手引入了一个完整的延迟时间。

  • TCP慢启动应用于每个新连接。

  • TCP流量和拥塞控制调节所有连接的吞吐量。

  • TCP吞吐量受当前拥塞窗口大小的限制。

因此,TCP连接可以在现代高速网络中传输数据的速率通常受到接收者和发送者之间的往返时间的限制。此外,当带宽持续增加时,延迟受光速限制,并且已经处于其最大值的小常数因子之内。在大多数情况下,延迟而不是带宽是TCP的瓶颈 - 例如,参见图2-5

§调整服务器配置

作为一个起点,在调整TCP中每个缓冲区和超时变量的任何特定值之前,有几十个,您只需将主机升级到最新的系统版本就更好。控制其性能的TCP最佳实践和底层算法继续发展,大多数这些更改仅在最新的内核中可用。简而言之,保持您的服务器是最新的,以确保发送方和接收方的TCP协议栈之间的最佳交互。

从表面上看,升级服务器内核版本似乎是微不足道的建议。然而,在实践中,它经常遇到显着的阻力:许多现有的服务器针对特定的内核版本进行调整,系统管理员不愿意执行升级。

为了公平起见,每次升级都带来了风险,但是为了获得最佳的TCP性能,也可能是您可以做出的最好的投资。

使用最新的内核,最好确保您的服务器配置为使用以下最佳做法:

增加TCP的初始拥塞窗口

更大的启动拥塞窗口允许TCP在第一个往返中传输更多数据,并显着加速窗口增长。

慢启动重新启动

在空闲之后禁用缓慢启动可以提高以周期性突发传输数据的长时间TCP连接的性能。

窗口缩放(RFC 1323)

启用窗口缩放可增加最大接收窗口大小,并允许高延迟连接实现更好的吞吐量。

TCP快速打开

允许在某些情况下在最初的SYN数据包中发送应用程序数据。TFO是一种新的优化,需要在客户端和服务器端都支持; 调查您的应用程序是否可以使用它。

上述设置和最新内核的组合将为单个TCP连接提供最佳性能 - 更低的延迟和更高的吞吐量。

根据您的应用,您可能还需要调整服务器上的其他TCP设置,以优化连接速率,内存消耗或类似条件。请参阅您的平台文档,并阅读HTTP工作组维护的“TCP Tuning for HTTP”文档以获取更多建议。

对于Linux用户来说,ss是检查开放套接字的各种统计信息的有用的电力工具。从命令行,运行 ss --options --extended --memory --processes --info以查看当前对等体及其各自的连接设置。

§调整应用程序行为

调整TCP的性能允许服务器和客户端为单个连接提供最佳吞吐量和延迟。然而,应用程序如何使用每个新的或已建立的TCP连接可能会产生更大的影响:

  • 没有比没有发送的更快; 发送较少的位。

  • 我们不能使这些位移动得更快,但是我们可以更靠近地移动位。

  • TCP连接重用是提高性能的关键。

消除不必要的数据传输当然是单一的最佳优化 - 例如,消除不必要的资源,或通过应用适当的压缩算法来确保传送最小位数。接下来,通过将世界各地的服务器(例如使用CDN)进行地理分配来定位靠近客户端,这将有助于减少网络往返延迟并显着提高TCP性能。最后,在可能的情况下,应该重用现有的TCP连接,以最大限度地减少由慢启动和其他拥塞机制所造成的开销。

§性能检查表

对于与您的服务器的每个新连接,优化TCP性能无论应用程序的类型如何,均支付高分红。提出议程的简短清单:

  • 将服务器内核升级到最新版本。

  • 确保cwnd大小设置为10。

  • 确保启用窗口缩放。

  • 空闲后禁止缓慢启动。

  • 调查启用TCP快速打开。

  • 消除冗余数据传输。

  • 压缩传输的数据。

  • 将服务器靠近用户,以减少往返时间。

  • 尽可能重用TCP连接。

  • 调查“TCP Tuning for HTTP”建议。

«返回目录

版权所有©2013 Ilya Grigorik。由O'Reilly Media公司发布,根据CC BY-NC-ND 4.0许可 。

share.gif

转载于:https://my.oschina.net/u/3373793/blog/885570

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值