高性能浏览器网络(High Performance Browser Networking)第一章
分类: 浏览器研究2013-09-2122:44 120人阅读 评论(0) 收藏 举报
performancenetworking高性能浏览器browser
第一章延迟和带宽的基本概念
过去几年内,Web性能优化(WPO)作为一个新的行业快速增长,成为用户追求更高的速度和更快的用户体验的一个明显标志。Web性能优化不单纯是一种快速连接世界的情感需要,也是很多关键业务需求驱动的结果:
- 更快的网站可以让更好的用户参与
- 更快的网站可以提升更好的用户回头率
- 更快的网站提升网站的转换率
简单地说,速度是一个重要特性。要实现这个特性,我们需要了解影响Web性能的诸多因素和基本限制。在本章中,我们将重点放在决定所有网络流量性能的两个关键部分:延迟和带宽(图1-1 )。
延迟一个数据包从源到目的地的时间带宽逻辑的或物理的通道容量
图1-1延时和带宽
为了更好的理解带宽和延迟是如何共同协作,我们将提供工具来更深入地研究TCP,UDP,以及上层应用协议的内部细节和性能特征。
低延迟的跨大西洋的高速光缆工程
在金融市场上,延迟是许多高频交易算法的重要影响因素,一个几毫秒的延时可能导致数以百万计的损失。
2011年初,华为和海伯尼亚大西洋网络( Hibernia Atlantic)开始铺设新的3000英里的光纤网络(“海伯尼亚快线”),这条高速光缆横跨大西洋连接伦敦到纽约,唯一的目标就是对比于所有其他现有的跨大西洋线路,能够节省5毫秒的延时。
一旦投入使用,这条电缆只被金融机构使用,这条光缆将耗资超过4亿美元,1毫秒的代价是8000万美元。由此可见,延迟的代价是昂贵的。
延迟是一个消息或者一个数据包从它的起始点到达目的地所花的时间。这个定义很简单,但它往往隐藏了许多有效的信息:每一个系统包含多个部件、多个影响因素,所有这些因素一起构成了消息传递的时间,了解系统由哪些部件组成,每一个部件的性能决定因素,对我们了解整个系统延迟至关重要。
让我们仔细的分析一下互联网的典型路由中常见的各种延迟因素,这些因素是如何影响一个消息从客户端传递到服务端。
传播延迟一个报文在从发送方到接收方所需的时间,传播延迟是指电磁信号或者光信号在传输介质中传输的时延,在光纤或者铜线中,光信号和电磁信号的传播速度都在20万公里/秒以上,在传输介质中传输的是电磁信号或者光信号,而不是数据!传输延迟在数据链路中传输所有数据包所需的时间,传输延迟与数据包的长度和链路的传输速度有关。处理延迟处理数据头、校验数据、查找数据包的目标地址所需的时间。排队延迟数据包在队列中等待时间
客户端和服务器之间的延迟时间是所有上述的延迟的总和。传播时间决定于距离以及信号的传播媒介 -在光纤,双绞线,电缆等传输媒体中,传播速率是固定的,而与发送的数据大小无关!传输延迟取决于可用的传输链路的数据速率,与在客户端和服务器之间的距离无关。举一个例子,让我们假设我们两个不同链路传输一个10 Mb的文件:1 Mbps和100 Mbps的链路,在1 Mbps的链路上我们需要10s才能把所有的文件放在整个链路上,而在100 Mbps的链路上,我们只需要0.1s。
接下来,一旦数据包到达路由器时,路由器必须检查数据包标头以确定即将下一跳的路由,同时可能还会对数据做其他的检查和处理,这都需要时间。这些处理大部分在硬件中执行,延迟非常小,但它们确实存在。最后,如果数据包到达速度比路由器处理速度快,那么数据包还需要在路由器的数据包队列中等待,这个等待时间被称为排队时延。
在网络上传输的每个数据包,都会遇到这些延迟。当源地址与目标地址越远,传播延迟越大;当数据包通过的中间路由越多,每一个数据包所需要的处理时间越多;同时当经历的路由越繁忙,数据包在路由器的等待缓冲区中停留的时间也越长。
路由器的过度缓存问题(Bufferbloat)
Bufferbloat是一个由Jim Gettys在2010年创建和普及的术语,主要描述的就是路由器的排队时延影响整体网络性能的一个很好的例子。
这个问题产生的原因就是现在很多路由器创建了很大的接收缓冲区,用来避免丢失数据包,然而,这种行为破坏了TCP的拥塞避免机制(我们将在下一章介绍),并引入变化的高网络延迟。
好消息是CoDel主动队列管理算法已经被提出来解决这个问题,现在已经实现在Linux 3.5 +内核。要了解更多信息,请参阅“控制队列延迟 “ACM队列。
正如爱因斯坦在他的狭义相对论中描述,光速是所有能量、物质和信息的可传播的最大理论速度。这个结论为任何网络的传播时间设定了无法超越的硬杠杠。
好消息是,光的速度很高:每秒299,792,458米,或者说每秒186282英里。但是,总有一个但是,这个是光在真空中的速度。实际应用中,我们的数据包总是通过某种介质来传输的,,比如铜线,或光纤电缆,这些介质都会减慢信号传输速度(表1-1 )。光速与光在介质中的传输速率比称为折射率,折射率越大,光在该介质中传输越慢。
典型的光纤的折射率值一般在1.4到1.6之间变化,当然,改善光纤材料质量,可以降低折射率。为了简化,经验法则是假设光纤中的光的速度是200,000,000米每秒,其对应的折射率为1.5左右。值得庆幸的是,我们已经实现了这样一个很高的速度了。这得感谢那些伟大的光通信工程师
表1-1.信号在真空和光纤的延迟
距离 |
真空传播时间 |
光纤传播时间 |
光前传播往返时间(RTT) |
|
纽约---旧金山 |
4148km |
14ms |
21ms |
42ms |
纽约---伦敦 |
5,585 km |
19ms |
28ms |
56ms |
纽约---悉尼 |
15993km |
53ms |
80ms |
160ms |
赤道周长 |
40075km |
133.7ms |
200ms |
200ms |
光的速度已经很快快,但从纽约到悉尼的一个往返(RTT)仍然需要160ms。事实上, 表1-1中的数字还是乐观情况,因为他们认为数据包通过光纤电缆沿大圆线(在地球上两点之间的最短距离,译者注:大圆线是球面上半径等于球体半径的圆弧。大圆线是连接球面上两点最短的路径所在的曲线。大圆线是球面上半径最大的圆弧,所有的經線都是大圆线,緯線則只有赤道而已)在城市间传输。在实际应用中,这样的电缆是不存在的,数据包在纽约和悉尼之间传输要经过更长的路由。沿着这条路由的每一跳将带来额外的路由,处理,排队和传输延迟。在我们现有实际的网络中,纽约和悉尼之间的实际RTT,基本在200-300ms之间。考虑所有的因素影响,似乎仍然相当快的,对不对?
我们不习惯于以毫秒为单位来衡量我们日常生活中的延迟,但研究表明,我们大多数人会去关注一个系统中超过100-200ms的延迟。一旦超过300毫秒的延迟阈值,交互往往定义为“疲软”,当超过了1000毫秒(1秒),很多用户在等待响应的过程中已经进行了心理上下文切换---也许开始白日梦,也许想到下一个紧急任务了。
结论很简单:为了提供最好的体验,让用户持续专注于当前的任务,我们需要我们的应用响应时间控制在几百毫秒内。这留给我们在网络上很少犯错的空间。为了达到这个目标,网络延迟需要重点被关注,并在应用开发的各个阶段有一个明确的设计标准。
内容交付网络(CDN)服务提供了许多便利,其最主要的一点就是通过简单的分析,将内容分布在全球各地,并通过从最近的位置为客户端提供内容,这将显著减少数据包的传播时间。
我们也许不能让数据包传播的更快,但我们可以通过策略性的方法将内容放在离用户更近的地方减少传播的距离!借助CDN,我们可以为数据传播带来显著的性能提升。
具有讽刺意味的是,实际情况往往不是穿越大洋或大陆,而是最后的几英里带来了更多的延迟:这就是臭名昭著的“最后一英里”的问题。为了将您的家里或办公室连接到互联网,你当地的ISP需要在临近的小区组建路由,合并信号,并将其转发到本地路由节点。在实际情况中,取决于连接的类型,路由方法,部署技术,也许需要消耗几十ms,而这只是为了接入到你的ISP的路由器!根据美国联邦通信委员会在2013年初进行的“宽带美国测量”的报告,在高峰时段:
光纤到户,平均延迟方面表现最好的,高峰时期平均为18毫秒,有线电缆延迟为26毫秒,而DSL则有44毫秒的延迟。 |
|
|
|
- FCC - 2013年2月 |
在数据包被发送到目的地前,我们仅发送到ISP的网络最近的节点已经就有18-44ms的延迟了。FCC的报告主要基于美国进行统计,但“最后一英里”的延迟问题是所有的互联网服务提供商的挑战,无论在哪个地域。如果你很好奇,一个简单traceroute经常可以告诉你你的互联网服务提供商的拓扑结构和性能情况。
$>traceroute google.com
traceroute to google.com (74.125.224.102), 64 hops max, 52 byte packets
1 10.1.10.1 (10.1.10.1) 7.120 ms 8.925 ms 1.199ms
2 96.157.100.1 (96.157.100.1) 20.894 ms 32.138 ms 28.928 ms
3 x.santaclara.xxxx.com (68.85.191.29) 9.953 ms 11.359ms 9.686 ms
4 x.oakland.xxx.com (68.86.143.98) 24.013 ms 21.423 ms19.594 ms
5 68.86.91.205 (68.86.91.205) 16.578 ms 71.938 ms 36.496 ms
6 x.sanjose.ca.xxx.com (68.86.85.78) 17.135 ms 17.978ms 22.870 ms
7 x.529bryant.xxx.com (68.86.87.142) 25.568 ms 22.865ms 23.392 ms
8 66.208.228.226 (66.208.228.226) 40.582 ms 16.058 ms 15.629 ms
9 72.14.232.136 (72.14.232.136) 20.149 ms 20.210 ms 18.020 ms
10 64.233.174.109 (64.233.174.109) 63.946 ms 18.995 ms 18.150 ms
11 x.1e100.net (74.125.224.102) 18.467 ms 17.839 ms 17.958 ms
第一跳:本地无线路由 |
|
11跳:谷歌服务器 |
在上面的例子中的数据包开始在桑尼维尔市的圣克拉拉,然后奥克兰,回到圣何塞,路由到了“529 Bryant”的数据中心,在这里,它被路由到谷歌服务器,第11跳到达了目的地。这整个过程中,平均来说,耗时18 ms。所有的事情考虑起来,情况不坏,但同时数据包也基本穿越了整个美国大陆大部分地方。
最后一英里延迟受你的ISP情况,部署技术,网络的拓扑结构,甚至一天不同时刻变化的影响。作为最终用户,如果你想提高你的网页浏览速度,降低延迟,选择本地延迟最小的ISP是一个优化的重要方法。
网络延迟而非带宽,是大多数网站的性能瓶颈!要理解其中缘由,我们需要了解TCP和HTTP协议 - 随后的章节中我们将涵盖这个主题。然而,如果你觉得好奇,可以直接跳到:“更高的带宽不起作用”。
采用Traceroute测量延迟
traceroute程序是一个简单的网络诊断工具,它用来记录数据包的路由路径以及路由中每一跳的延迟。为了标识出路由中的每一跳,它以递增的TTL发送一个数据包序列到目标地址。当TTL达到上限,中间路由将返回一个ICMP已超时“消息,Traceroute工具用这个来衡量每个网络跳的延迟。
在Unix平台上命令行名称为traceroute,在Windows上,命令行名称为tracert。
光纤,作为一个简单的“光管”,略粗于人的头发,用来传输的电缆两端之间的光信号。金属线也可以用来传输,但金属线有更高的信号损耗,电磁干扰,以及更高的维护成本。数据包在传输过程中可能会同时经过这两种介质,但对于任何长距离传输,光纤是不可避免的。
光纤具有明显的带宽优势,因为每个光纤可以携带许多不同的光的波长(信道),这就是波分复用(WDM)技术。因此,光纤链路的总带宽,是每个通道的数据传输速率和复用信道数量的乘积。
截至2010年初,研究人员已经研究出超过400路波长复用的技术,每个通道带宽达到171 Gbit / s,每一个光纤链路的总带宽可以超过70 Tbit/秒!我们需要成千上万的铜线(电)才能达到这个吞吐量。这并不奇怪,长距离传输,如大洲之间的海底数据传输都是通过光纤链路进行。每根电缆包含多股光纤(4股是一种常见的数),它转换成每根电缆数百T bit/s的带宽容量。
骨干网,或者说光纤链路,组成互联网的核心数据路由,能够传输数百Tbit/s的数据。然而,接入网的可用容量,要少得多,而且随着不同的接入技术变化很大:拨号,DSL,有线电缆,基于主机的无线技术,光纤到户,本地路由器的性能。用户的可用带宽是在客户端与目标服务器(图1-1 )之间传输链路中,属于最低的一环。
AkamaiTechnologies公司经营全球性的CDN,在全球各地部署服务器,并提供免费的季度报告, 表1-2显示了2013年第一季度的带宽趋势。
表1-2。Akamai的服务器上显示的2013年第一季度的平均带宽
国家/地区 |
平均Mbps的 |
同比变化 |
|
- |
。 |
3.1 |
17% |
1 |
韩国 |
14.2 |
-10% |
2 |
日本 |
11.7 |
− 3.6% |
3 |
香港 |
10.9 |
16% |
4 |
瑞士 |
10.1 |
24% |
5 |
荷兰 |
9.9 |
12% |
... |
|||
9 |
美国 |
8.6 |
27% |
上述数据不包括来自移动运营商的流量,我们会在后续的章节中来讨论这个话题的细节。目前来看,移动带宽变化很大,而且总体是更慢一些。然而,即使不考虑移动带宽,在2013年初全球宽带平均带宽仅为3.1 Mbps!韩国的14.2 Mbps的带宽居世界领先地位,美国排在第九位为8.6 Mbps。
为了更清楚的了解这一点,我们考虑一下高清视频流,一般需要2-10 Mbps的带宽,这依赖于视频分辨率和编码格式。因此,目前平均带宽,普通用户可以用来播放低分辨率的视频流,这已经占用了用户的大部分带宽了,如果一个家庭中有多个用户想同时看视频,基本上就属于不靠谱的故事了。
搞清楚用户的带宽瓶颈在哪里是一件不简单但很重要的工作。有许多的在线服务,如由Ookla提供的speedtest.net( 图1-2 ),它提供了一些本地服务器的上行和下行速率的测试服务-我们将在TCP章节来讨论为什么挑选一个好的本地ISP这么重要。在这些服务上运行一个测试,可以很好的检查您的连接速度是否符合您当地的ISP所宣传的速度。
图1-2上行和下行速度测试(speedtest.net)
虽然选择一个高带宽链路的ISP是必须的,但也不能保证稳定的端到端的性能。网络可能在某一个时间点由于高负荷,硬件故障,集中的网络攻击,或其他主机原因在中间任何一个节点拥塞。高吞吐量和延迟性能的变化是我们的数据网络的固有属性 - 预测,管理和适应不断变化的“网络天气”是一项复杂的任务。
我们对更高带宽的需求正在快速增长,在很大程度上是由于日益普及的视频流需求,目前视频流基本占到了整个互联网一半的带宽。好消息是,虽然它可能不便宜,有多种技术为我们提供增长的可用容量:我们可以在我们的光纤链路中添加更多的光纤,我们可以在拥塞的路线部署更多的链路,我们也可以改善WDM技术,让其在现有的链接中传输更多的数据。
电信市场研究和咨询公司TeleGeography估计,截至2011年,我们仅使用了部署的海底光纤链路可用容量的20%。更重要的是,在2007年和2011年之间,一半以上所有新增跨太平洋电缆是由于WDM技术升级:在相同的光纤链路的两端,可以传输更多的数据。当然,我们不能指望这些提升无限制地进行下去,因为每一个介质都会达到其收益递减点。尽管如此,只要经济允许,我们没有理由不去增加带宽 - 即使新技术都失败了,我们还可以部署更多的光纤链路。
降低延迟是另外一个不同的的故事。我们可以通过开发更低折射率的材料和更快的路由器让我们一点点接近光的速度。然而,我们目前的光纤传播速度是折射率约为〜1.5,这意味着理论上我们最多提高30%。不幸的是,我们没有办法解决物理定律 - 光速的最低延迟的硬性限制。
因此,我们不能让光信号传输更快,但我们可以使短的距离 -地球上任意两点之间最短的距离被定义为它们之间的大圆路径。然而,新电缆不可能完全按照大圆路径来铺设,这关系到地形,社会和政治等因素,同时也受到成本的限制。
因此,为了提高我们的应用性能,我们需要基于现有带宽和光传输速率的限制设计和优化好我们的协议:减少传输路由节点,在离客户端更近的地方部署数据,在应用中通过缓存、预取和其它技术来隐藏网络的延迟。
高性能浏览器网络(High Performance Browser Networking)第二章
分类: 浏览器研究2013-09-2123:27 175人阅读 评论(0) 收藏 举报
第2章 TCP篇
互联网的核心是两个协议,IP和TCP。 IP也叫Internet协议,提供主机到主机的路由和寻址;TCP,传输控制协议,在不可靠的传输通道上提供一个可靠的网络抽象。TCP / IP协议也通常被称为Internet协议套件,在1974年,它首次在一篇题为《一个用于分组网络互通的协议》的论文中被Vint Cerf和Bob Khan提出。
最初的RFC建议(RFC 675)几经修订,在1981年发表TCP / IP V4正式规范,但分为了两个独立的RFC:
- RFC 791 - Internet协议
- RFC 793 - 传输控制协议
从那时起,有一些增强建议补充到TCP协议中,但核心没有大的改变。TCP迅速取代了以前的协议,成为了现在许多最流行的应用程序的首选协议:万维网,电子邮件,文件传输,和其他许多应用。
TCP在不可靠的传输信道上提供了可靠传输的抽象,隐藏了我们的应用程序大部分的复杂性功能:丢包重传,按序传送,拥塞控制和避免,数据完整性,其他特性。当您使用TCP流,TCP协议保证您的所有字节发送与接收的数据是相同的,他们会以相同的顺序到达对端。TCP设计为一个顺序发送协议,而不是一个定时发送协议,这为我们Web性能优化带来了很大的挑战。
HTTP协议并没有指定TCP为唯一的传输协议。如果我们需要,我们完全可以基于数据报套接字(UDP)或任何其他传输协议实现HTTP通信,但在实际应用中,在互联网上所有HTTP通信都是通过TCP传送。
正因为如此,了解TCP的一些核心机制是Web性能优化必不可少的知识。实际情况是,你可能不会在应用中直接使用TCP套接字,但你在应用层选择的设计方案,将影响您的应用程序在TCP层和底层网络的性能。
交错的TCP和IP协议历史
我们都熟悉IPv4和IPv6,但IPV {1,2,3,5}的情况是咋样的?IPv4中的4代表了TCP / IP协议的第四个版本,这是在1981年9月发布的版本。最初的TCP / IP草案分裂成的两个草案,到了V4版本,TCP/IP正式分裂两成单独的RFC。因此,IPv4中的V4只是一个版本继承关系 - V4既不是比IPv1,IPv2,IPv3有更高的优先级,也不存在单独的IPv1, IPv2,或IPv3协议。
1994年,IETF工作组开始研究“互联网下一代协议”(IPng)时,他们需要一个新的版本号,但V5已分配给另一个实验协议:联网流协议(ST),因此他们选用了V6。事实证明,ST从未发展起来,这就是为什么很少有人听说过它。
三次握手
所有TCP连接开始前必须进行三次握手( 图2-1 )。在任何应用中,客户端或服务器在进行数据交换之前,他们必须先协商起始数据包序列号,其他一些连接参数。出于安全考虑,双方一般都是随机挑选起始序列号。
图2-1三次握手
SYN 客户端挑选一个随机序列号x,同时发送一个SYN包,SYN包中也可能包括额外的TCP标志和选项。 SYN ACK 服务端在x上增1,同时挑选一个服务端随机序列号y,附加服务端的一些标志和选项,发送给客户端 ACK客户端在x y基础上都增加1,并发送一个ACK包服务器,完成了握手过程。
一旦三次握手完成后,应用程序数据可以开始在客户端和服务器之间传输。客户端可以在发送完ACK包后立刻发送数据包,但服务器必须在收到ACK之后才能发送任何数据。这个握手过程适用于每一个TCP连接,并给所有使用TCP的网络应用程序性能带来了重要影响:任何应用程序在数据传输之前,新的TCP连接都将有一个固定的往返延迟。
例如,如果客户端在纽约,服务端在伦敦,我们通过光纤链路建立一个新的TCP连接,那么三次握手将至少需要56毫秒( 表1-1 ):单向传播需要28ms,往返一次需要56ms(译者注:客户端只要在收到SYN ACK后就可以发送数据了)。需要注意的是,这和连接带宽没有直接关系。实际上,延迟是由客户端和服务端的信号传播延迟造成,也就是光信号的从纽约到伦敦的传播时间。
创建新的TCP连接所需要的三次握手延迟是很明显的,这也是重用TCP连接是任何应用程序的优化的关键手段的原因之一。
TCP快速连接
TCP的三次握手已被确定为Web延迟的一个重要因素,在很大程度上也是由于网页浏览时通常需要访问几十个甚至上百个来自不通过主机的内容。
TCP快速创建(TFO)是一种旨在减少新的TCP连接延迟的机制。基于在谷歌完成的对流量分析和网络模拟,研究人员已经证实通过TFO机制,允许在SYN包中携带数据,可降低HTTP网络延迟了15%,整体页面加载时间平均可以降低10%以上,并在某些高延迟的场景下,可降低高达40%。
在Linux 3.7 +内核中,客户端和服务端目前都已可支持TFO,这将成为客户端和服务端的一个新选择。尽管如此,TFO不是每一个问题的解决方案。虽然它可能有助于消除三次握手来回的延迟,但是它只能应用与特定场景:SYN数据包的有效荷载大小有限制,只有某些类型的HTTP请求可以被发送;它仅适用于重复连接请求,因为每个新的请求有加密cookie的要求。如果想对TFO的能力和限制行了详细的了解,可以查看最新的IETF草案“TCP Fast Open”。
拥塞避免和控制
1984年初,Jhon Nagle描述了“拥塞崩溃”场景,这在任何非对称网络中都有可能出现:
在复杂的网络中,拥塞控制是一个公认的问题。我们已经发现,国防部的互联网协议(IP)-- 数据报协议,以及传输控制协议(TCP)--- 传输层协议,当把它们一起使用时容易遭受不寻常的拥塞问题,这是由在传输层和数据报层之间的相互作用而引起的。特别的,IP网关对于被我们称为“拥塞崩溃”的现象而言是脆弱的,特别是当这种网关连到大范围的不同带宽的网络上的时候... 如果任何主机的数据包的传输往返时间超过了最大重传阀值,该主机将开始发送越来越多重传包到网络中。这时网络就处于一种麻烦状态了。最终交换路由节点的缓冲区被塞满,新的数据包必须被丢弃。数据包的往返时间超出了上限,主机上每个数据包都要发送好几次,最终这些重复包中的一部分到达了目的地。这就是拥塞崩溃。 这种情况是持续的。一旦已达到拥塞点,如果丢弃算法是无优先级的,网络将持续处于拥塞状态。 |
|
|
|
- John Nagle - RFC 896 |
该报告指出,拥塞崩溃在ARPANET中不会成为一个问题,因为大多数节点有统一的带宽,骨干网有很大的容量。然而,这些断言早已变成了现实。在1986年,当网络节点超过5000个时,且不同的网络节点在持续增加时,一系列的拥塞崩溃事件横扫整个网络 - 在某些情况下,网络变得基本无法使用。
为了解决这些问题,多个机制被提出来用来控制拥塞:流量控制,拥塞控制和拥塞避免机制。
高级研究计划署网络(ARPANET)是现代互联网的前身,也是世界上第一个业务分组交换网络。该项目于1969年正式推出,并在1983年TCP / IP协议作为主要的通信协议取代了早期的NCP(网络控制程序)。其余的,正如他们所说,都变成了历史。
流量控制
流量控制是一种控制发送方过量发送数据给接收端的机制,-接收端可能因为高负荷,处于繁忙状态,也可能接收端只分配了固定大小的缓冲区。为了解决这个问题,TCP连接的每一方都会宣告(图2-2 )自己的接收窗口(rwnd值),用来知会对方自己的数据接收缓冲区大小。
图2-2接收窗口大小(RWND)
当连接首次建立时,双方都采用系统的缺省设置值来初始化他们的rwnd,一个典型的Web页面将缓存从服务器到客户端的大部分数据流,客户端的缓冲区就有可能成为瓶颈。然而,如果客户端传输流数据到服务器,例如在一个图像或视频的情况下,大量的上传数据,则服务器接收窗口可能成为瓶颈。
如果出于任何原因,一方如果不能处理,那么它可以更改成一个较小的窗口,并通知对方。如果该窗口大小变为零,则它被视为一个信号:不要发送更多的数据,直到应用层处理完所有缓冲区中的数据。此更新过程在每个TCP连接的整个生命周期中持续:每个ACK报文中携带最新的rwnd值,让双方可以动态地调整数据流速和处理速度。
窗口缩放(RFC 1323)
最初的TCP规范分配了16 bit来设置接收窗口大小,这意味着可以设置的最大值为 (216, or 65,535bytes) .事实证明,为了获得最佳的性能,这个上限往往是不够的,尤其是具有高带宽延延迟乘积“的网络中。
为了解决这个问题,RFC 1323制定了一个“TCP窗口缩放”选项,这使我们能够提高接收窗口大小从65,535字节到1G bits!窗口缩放选项在三次握手过程中进行交换,在这个字段中携带了一个值,它用来表示后续ACK16bit需要左移的位数。
今天,TCP窗口缩放选项在所有主要平台下默认情况下都是启用的。然而,中间节点,路由器和防火墙可以重写,或甚至清除此选项 -如果您的服务端或者客户端连接,无法充分利用可用带宽,可以检查一下接收窗口大小,这是一个好的开始。在Linux平台下,窗口缩放设置可以通过以下命令查看或者启用:
- $> sysctl net.ipv4.tcp_window_scaling
- $> sysctl -w net.ipv4.tcp_window_scaling=1
慢启动
尽管TCP存在流量控制机制,网络拥塞崩溃依然在1980年代中后期成为一个严峻的问题。问题是,前面提到的流量控制机制可以防止发送端发送过量数据给接收端,但是没有一个好的机制,可以防止发送端还是接收端侵蚀底层基础网络:在TCP连接建立的时候,无论发送方还是接收方,都无法清楚知道中间网络的可用带宽,因此我们需要一种机制来评估它,并能使调整发送速度使其适应不断变化的网络条件。
我们举一个例子来说明这种调节机制是有价值的,想象一下你在家里,正在播放一个在线视频流,服务器以你家里最大的下行带宽下发数据,确保您的最佳体验。这时,家庭网络上的另一个用户打开一个新的连接,下载一些软件更新。突然之间,分配给视频流可用的下行链路带宽下降很多,在这种情况下,视频服务器必须调整其下发数据速率 -如果它继续以之前的速率,数据将堆积在中间的某个节点上,数据包将被丢弃,网络使用效率极其低下。
1988年,Van Jacobson和 Michael J.Karels发布了一些算法来解决这些问题:慢启动,拥塞避免,快速重传和快速恢复。这四个算法迅速成为了TCP强制性规范的一部分。事实上,人们普遍认为,正是这些更新算法使得在上世纪80年代和90年代初的流量以指数速度继续增长情况下,网络避免了崩溃。
要了解慢启动,最好是看它的实际操作。我们再来看一下我们在上一章提到的例子,假设客户端在纽约,试图从伦敦的服务器中下载一个文件。首先,客户端和服务端进行三次握手,在此过程中,双方在ACK数据包中设置他们的各自的接收窗口(rwnd值)大小(图2-2 )。一旦最后的ACK包发出,我们就可以开始交换数据了。
我们要计算底层可用网络带宽的唯一方法就是在客户端和服务端交换数据的过程中进行逐步测量,这也是慢启动算法要干的事情。开始时,服务端为每一个新的TCP连接初始化一个拥塞窗口(cwnd的)值,cwnd的初始值一般是一个系统的缺省值(在Linux下是 initcwnd变量)。
拥塞窗口大小(cwnd)代表服务端能够发送出去的但还没有收到ACK确认的最大数据报文段长度
cwnd变量不会在发送端和接收端之间进行交换 -在这个例子中,cwnd是在伦敦的服务器维护一个私有变量。前面我们讨论过的rwnd,加上这里的cwnd,TCP定义了一个规则:在客户端和服务端之间未确认的数据包的最大值为min(rwnd,cwnd)。到目前为止,一切貌似都很好,但服务端和客户端如何确定拥塞窗口的最优值?毕竟,网络条件随时在变化,即使是相同网络中的两个节点之间,我们也不想去手动调节cwnd值,如果有一种自动调整的算法将非常棒!
解决的办法是先慢慢的发送,随着数据包被确认,逐步增大窗口大小 -这就是慢启动的核心思想!最初,cwnd的值设置为一个TCP Segment,1999年4月的RFC 2581更新这个值至最多四个TCP Segment,2013年4月RFC 6928将这个值更新到了最大10个TCP Segment。
一个新的TCP连接建立后,每次能发送的最大未确认数据包大小是min(cwnd,rwnd),因此,服务端可以发送4个TCP Segment到客户端,然后他要等待数据包的ACK确认。每收到一个ACK,慢启动算法定义发送端的cwnd值可以增加一个TCP Segment - 这意味着每确认了一个数据包,两个新的数据包可以被发送。这个阶段通常被称为“指数增长”(图2-3 )阶段,客户端和服务端都试图快速地占用他们之间可用的带宽。
图2-3拥塞控制和拥塞避免
那么,为什么慢启动是我们创建Web应用需要考虑的一个重要因素?因为HTTP和许多其他应用协议运行在TCP之上,不管可用带宽是多大,每一个TCP连接必须要经过慢启动阶段 - 我们不能一开始就使用全量的链路容量!
实际上,我们开始用小拥塞窗口,在发送成功后窗口大小扩展一倍 -即指数增长。其结果是,达到特定的阀值(客户端和服务端之间的最大带宽)所需要的时间与(公式2-1 )在客户端和服务器之间的往返时间RTT,初始拥塞窗口大小的关系如下:
Equation 2-1.Time to reach the cwnd size of size N
\begin{aligned}\mathrm{Time} = \mathrm{RTT} \times \left\lceil log_2 \left( \frac{\mathrm{N}}{\mathrm{initial\cwnd}} \right) \right\rceil \end{aligned}
让我们假设以下情形:
- 客户端和服务器接收窗口(rwnd):65,535字节(64 KB)
- 初始拥塞窗口(cwnd):4 TCP Segments(RFC 2581)
- RTT时间为56毫秒(伦敦,纽约)
在这个例子中,我们将使用旧的(RFC 2581)4个TCP Segments为拥塞窗口的初始值,因为它仍然是目前大部分服务器最常用的值。通过下面例子的演示,你可能觉得你有必要去更新你的服务器了!
尽管接收窗口大小(rwnd)大小设置为64 KB,但是根据我们前面定义的,TCP连接建立后,初始的最大数据包大小为min(rwnd,cwnd)。因此事实上,要达到64 KB的限制,我们将需要拥塞窗口大小(cwnd)增长到45 TCP Segments,这将需要224毫秒:
\[\begin{aligned} \frac{65,535\ \mathrm{bytes}}{1460\ \mathrm{bytes}}&\approx 45\ \mathrm{segments} \\ 56\ \mathrm{ms} \times \left\lceillog_2 \left( \frac{45}{4} \right) \right\rceil &= 224\ \mathrm{ms}\end{aligned} \]
需要4个往返RTT( 图2-4 ),几百毫秒的延迟,客户端和服务器之间的吞吐量才能达到64 KB!因此事实上,对于一些客户端和服务端可以达到Mbps+的连接,慢启动没有任何效果。
图2-4拥塞窗口大小的增长
为了减少拥塞窗口增长所需要的时间,我们可以减少客户端和服务器之间的往返时间RTT -例如在靠近客户端的地方部署服务器。或者,我们可以增加初始拥塞窗口大小到新的RFC 9828值10 TCP Segments。
慢启动对于大文件下载,流媒体下载来说不是问题,客户端和服务端消耗几百ms达到他们之间的最大速度 -这个相对于总的下载时间来说,微不足道。
然而,对于许多HTTP连接来说,请求是短小且突发的,大部分情况下,还没有达到最大阀值时,请求已经结束了。结果是,很多web应用的性能受到负向影响:因为慢启动需要更长时间达到最大速率,尤其对小请求来说,影响更大。
慢启动重启
除了调节新TCP连接的传输速率,TCP协议还实现了慢启动的重新启动机制(SSR),当一个连接空闲了一段时间后,将重置拥塞窗口(cwnd)。理由很简单:当连接闲置的时候,网络条件可能已经改变,为避免拥塞,拥塞窗口复位到一个“安全”的默认值。
很显然,SSR对那种应对突发请求的长TCP连接有很大的性能影响 - 例如HTTP的keep-alive请求。因为一旦被重置后,遇到突发请求时,又得经历慢启动的过程,而如上面描述,性能很低。所以在这种情况下,建议在服务器上禁用SSR。在Linux平台上的SSR设置可以通过下面的命令进行查看和禁用SSR:
- $> sysctl net.ipv4.tcp_slow_start_after_idle
- $> sysctl -w net.ipv4.tcp_slow_start_after_idle=0
为了说明三次握手和慢启动阶段对一个简单HTTP的影响,让我们假设在纽约的客户端向在伦敦的服务端请求一个20 KB的文件( 图2-5 ),连接参数如下:
- 往返时间(RTT):56ms
- 客户端和服务端之间的带宽:5 Mbps
- 客户端和服务端的接收窗口(rwnd):65,535 bytes
- 初始拥塞窗口大小(cwnd): 4 segments (\(4 \times 1460\ \mathrm{bytes} \approx 5.7\ \mathrm{KB}\))
- 服务端处理时间:40ms
- 无丢包,每包都要求ACK确认,GET请求装入单个TCP Segment
图2-5通过新的TCP连接获取一个文件
客户端开始TCP握手---SYN |
|
28 ms |
服务端响应SYN-ACK和指定其RWND的大小 |
56 ms |
客户端发送ACK SYN-ACK,指定其RWND的大小,并立即发送HTTP GET请求 |
84 ms |
服务器接收到HTTP请求 |
124 ms |
服务器构建20 KB的响应,发送4 TCP Segments给客户端,并暂停等待ACK确认(初始拥塞窗口大小为4 TCP Segments) |
152 ms |
客户端收到4个TCP Segments,每一个TCP Segment发送一个ACK确认 |
180 ms |
服务端收到每个ACK,cwnd递增1,最终发送8个TCP Segments出去 |
208 ms |
客户端收到8个 TCP Segments并ACK确认每一个Segment |
236 ms |
服务器收到每个ACK后,将CWnd增1,并发送剩余的Segments |
264 ms |
客户端收到剩余的TCP Segments,并ACK确认每一个Segment |
作为一个练习,我们将初始拥塞窗口设置为10 TCP Segments图2-5,我们应该可以发现可以少一个完整的往返网络延迟 - 在性能上提高了22%!
在一个RTT为56ms的TCP连接上传输一个20KB的文件,将消耗掉264ms的时间。相比之下,让我们假设客户端是能够重复使用同一个TCP连接(图2-6 ),再次发出同样的请求。
图2-6在现有的TCP连接上获取一个文件
客户端发送HTTP请求 |
|
28 ms |
服务端接收HTTP请求 |
68 ms |
服务端完成生成20 KB响应,目前拥塞窗口值已经大于发送文件所需的15 TCP Segments,因此它会一次性发送出所有数据。 |
96 ms |
客户端接收所有15 TCP Segments,ACK确认每一个Segment |
在同一连接上执行了同样的请求,但现在没有三次握手的成本和慢启动阶段的延迟,消耗的时间为96ms,达到了275%的性能提升!
在上面两个例子中,服务端和客户端之间的5 Mbps的上行带宽对性能没有实质性影响,相反,传播延时,和拥塞窗口大小是关键影响因素。
事实上,在同一个TCP连接上第一个请求和第二个请求之间的性能差距只与客户端和服务端之间的RTT有关,你可以尝试着调整上面的参数试试看。
增加TCP的初始拥塞窗口(cwnd)
把服务端的初始拥塞窗口更新为新的RFC 6928值(10 TCP Segments,简称IW10),是一个提升性能简单的方法。这可以让所有用户和所有基于TCP的应用受益。好消息是,许多操作系统在新的内核中已经更新了 - 你可以检查相应的文档和发行说明。
对于Linux,所有2.6.39以上内核版本的缺省值都是IW10了。但是,不要停在那里:升级到3.2 +还可以得到其他好处,比如“按比例缩减(PRR)”。
拥塞避免
我们需要认识到,TCP设计时将丢包作为一个性能的反馈,并用其来调节网速。换言之,它不是假设要发生丢包,而是当丢包发生时,会去调整。慢启动初始化一个保守的拥塞窗口大小(cwnd),在后面,每一个成功的确认,成倍的数据被发送,直到它超过接收端的流量控制窗口大小(rwnd:系统配置的拥塞阈值窗口),或者当丢失了一个数据包,拥塞避免算法(图2-3 )将开始起作用。
拥塞避免算法隐含的假设是一旦发生了网络丢包 -网络路由的某处发生了拥塞,*丢弃该数据包,因此我们需要调整我们的窗口,以避免诱发更多的网络丢包。
一旦拥塞窗口被复位后,拥塞避免算法设定拥塞窗口增长算法,以尽量避免进一步的丢包。在某一个时间点,丢包事件又发生了,这个过程会重复的执行一次。如果你曾经看过一个TCP连接的吞吐量跟踪图,你可以观察到有很多的锯齿纹,现在你应该知道它为什么看起来这样 - 这是拥塞控制和避免算法在不停的控制拥塞窗口的大小以避免网络丢包。
最后,值得注意的是,改善拥塞控制和拥塞避免的算法在学术研究和商业产品中都是一个活跃的领域,不同的网络类型,不同类型的数据传输,有不同的优化算法。今天,在不同平台上,可能运行着许多变种的算法:TCP Tahoe andReno(原始实现),TCP Vegas,TCP New Reno,TCP BIC,TCPCUBIC(Linux上的默认实现),或 Compound TCP(Windows的默认实现),还有其他很多种实现方案。然而,无论如何实现,都是为了解决拥塞控制和拥塞问题。
快速恢复算法(PRR)
一旦发生了丢包,我们需要复位拥塞窗口,但如何以最佳的方式恢复拥塞窗口是一个简单的挑战:如果你是过于激进,那么间歇性的丢包将显著影响整个连接的吞吐量,如果你调整的速度不够快,那么你可能丢失更多的包。
本来,TCP用“加增乘减”(AIMD)算法:当发生丢包,拥塞窗口大小减半,然后慢慢增加窗口大小。然而,在许多情况下,AIMD算法是过于保守,因此新的算法被开发。
PRR是RFC 6937中指定的一种新的算法,其目标是当一个数据包丢失时,提高恢复速度。他到底优化了多少呢?根据谷歌开发新算法进行测量,它可以减少3-10%的延迟。
PRR现在是Linux 3.2 +内核默认的拥塞避免算法 -这也是一个很好的理由去升级你的服务器!
带宽延迟乘积(BDP)
内置的TCP拥塞控制和拥塞避免机制包含了另外一重要含义:最佳的发送方和接收窗口的大小(rwnd)必须根据它们之间的往返时间(RTT)和数据传输速率的不同而有所差异。
要理解为什么,我们先回忆一下前面的结论:发送端和接收端之间未确认的最大数据包(没有接收到ACK的包)大小为min(cwnd,rwnd):rwnd将在每一个ACK中更新,拥塞窗口大小(cwnd)则根据拥塞控制和避免算法的基础上由发送者进行动态调整。
如果发送端或接收端未确认的数据包超过了上限,他们必须暂停发包,等待另一端的ACK包,然后继续发送。他们必须等待多久?这取决于它们之间的往返时间!
带宽延迟乘积(BDP)数据链路的容量和终端到终端的延迟的乘积。其结果是在任何一个时间点接收端和发送端之间最大的未确认数据包大小值。
如果发送端或接收端经常*停下来,等待以前包的ACK,那么这将在数据流中形成空当( 图2-7 ),这将限制连接的最大吞吐量。为了解决这个问题,该窗口尺寸应该设计的足够大,使得另一端在前面的数据包ACK到达之前也能继续发送数据, - 无间隙,才能达到最大的吞吐量。因此,最佳的窗口大小是依赖的往返时间(RTT)!选择了一个较低的窗口大小,这将会限制连接的吞吐量,不管这两端之间可用的或者标榜的带宽有多大。
图2-7由于低拥塞窗口导致的传输空当
那么,rwnd和cwnd的值设置为多大才是合适的呢?实际计算是很简单。首先,我们假设,最低的cwnd和RWND的窗口大小是16KB,之间的往返时间是100ms:
\[\begin{aligned} 16\ \mathrm{KB} = (16 \times 1024 \times 8) &=131,072\ \mathrm{bits}\\ \frac{131,072\ \mathrm{bits}}{0.1\ \mathrm{s}}&= 1,310,720\ \text{bits/s}\\ 1,310,720\ \text{bits/s} =\frac{1,310,720}{1,000,000} &= 1.31\ \mathrm{Mbps} \end{aligned} \]
无论发送端或接收端之间的可用带宽是多少,这个TCP连接不会超过1.31 Mbps的数据传输速率!为了实现更高的吞吐量,我们需要提升的最小窗口大小,或者降低的往返时间(RTT)。
同样地,如果我们知道往返时间(RTT)和两端的可用带宽,我们也可以计算出最佳的窗口大小。在这种情况下,让我们假定保持不变的往返时间(100ms),而发送方的可用带宽为10 Mbps,和接收器端拥有100 Mbps+的可用带宽。假设它们之间没有任何网络拥塞,我们的目标是,充分利用这个10 Mbps的链接:
\[\begin{aligned} 10\ \mathrm{Mbps} = 10 \times 1,000,000 &=10,000,000\ \mathrm{bits/s}\ \\ 10,000,000\ \text{bits/s} =\frac{10,000,000}{8 \times 1024} &= 1,221\ \text{KB/s}\\ 1,221\\mathrm{KB/s} \times 0.1\ \mathrm{s} &= 122.1\ \mathrm{KB} \end{aligned} \]
窗口的大小至少需要122.1 KB,才能充分利用这10 Mbps的链路。前面我们在流量控制章节中讨论过,最大TCP接收窗口大小为64 KB,除非“窗口缩放(RFC 1323)”是支持的-仔细检查你的客户端和服务端的设置!
好消息是,窗口大小协商和调整被网络协议栈自动管理并进行相应的调整。坏消息是,有时它仍然是TCP性能的影响因素。如果你曾经碰到过下面的情况,你的传输速度只占用了可用带宽的一小部分,甚至你知道无论是客户端和服务端能够拥有更高的速率,你需要检查一下是否是窗口设置过小:对端小的接收窗口,不稳定的网络,高丢包导致的拥塞窗口复位,或显式的流量模型都有可能影响到您的网络吞吐量。
高速局域网中的带宽延迟乘积
BDP是一个与往返时间(RTT)和数据速率相关的函数。虽然RTT可能是高传播延迟网络中常见的瓶颈,但是RTT也可能成为本地局域网上的瓶颈!
在1 ms RTT的局域网中,要达到1 Gbit / s速率,我们需要一个至少122 KB的拥塞窗口。计算过程和上面是完全一样的,我们简单地在目标数据传输速率上增加几个0,在往返RTT中减少同样的几个0。
线头阻塞
TCP提供了一个运行在不可靠信道上的可靠的网络抽象,其中包括基本的数据包错误校验和纠错,按顺序传输,重传丢包,以及流量控制,拥塞控制和拥塞避免等提升网络性能的特性。正是TCP拥有这些特点,使得TCP成为大多数应用程序的首选传输协议。
然而,尽管TCP是一种普遍的选择,但不是唯一的,在某些场景下,也不一定是最佳的选择。特别是,顺序发送和可靠传输这样的特性并不总是必要的,可能引起不必要的延误和负向的性能影响。
要理解为什么,我们记得每一个TCP数据包带有一个唯一的序列号,在传输时,数据必须按顺序传递给接收端(图2-8 )。如果某个包在接收端的接收缓冲区中丢失,则所有后续数据包必须被放在接收端的缓冲区中,直到重传包到达接收端。因为这个工作在TCP层完成,我们的应用程序无法感知底层的重传,也无法直接查看底层的缓冲区,应用程只有等待所有的数据包接收完毕后才能处理数据。相反,它只是看到从socket中读不到数据或者读取数据延迟,这种效应被称为TCP的线头(HOL)阻塞。
图2-8 TCP线头阻塞
线头阻塞虽然带来了延迟,但它避免了我们的应用程序去处理重新排序包和重新组装包的工作,这使得我们的应用程序代码要简单得多。然而,这带来了数据包到达时间的不可预知性-通常称为抖动 -这对应用程序的性能产生了负向影响。
此外,一些应用程序可能根本不需要可靠传输,或者顺序传输:如果每一个数据包是一个独立的消息,则按序传输是不必要的,如果每个消息将覆盖所有以前的消息,可靠传传输也完全没有必要。不幸的是,TCP不提供这样的配置 - 所有的包必须按序传输。
能够容忍和自行处理包的乱序或者丢包的应用,或者对延迟和抖动敏感的应用,可以考虑另外一个选择:UDP。
丢包是可以的
事实上,以获得最佳的性能从TCP,丢包是必要的,丢弃的数据包作为一个网络状态反馈机制,接收端和发送端依据它来调整发送速率以避免网络拥塞,降低延迟-见“本地路由器的Bufferbloat” 。此外,一些应用程序容忍数据包丢失而不受影响:音频,视频和游戏状态更新等应用程序的数据不需要可靠和按序传输 - 顺便说一句,这也是为什么WebRTC使用UDP作为传输协议。
如果一个数据包丢失,音频编解码器可以简单的在音频中插入一个小暂停,并继续处理传入的数据包。如果间隙足够小,用户可能根本察觉不到,而等待丢失的包可能带来更多暂停的风险,这也将导致的更差的用户体验。
同样,如果我们在一个3D的世界去更新一个游戏状态,然后等待一个T-1时间点的数据包来描述其状态时,这时我们收到了时间T的状态,这种情况下T-1时间点的状态就没有必要了,我们收到每个消息后直接更新,可以接收间歇性的丢包,这不影响游戏的体验。
TCP协议作为一种自适应协议,设计的目标是所有网络节点具有同等地位,有效的利用底层网络。因此,优化TCP的最好方法就是让TCP感知网络条件和针对上层和下层的需求调整自身的行为:无线网络可能需要不同的拥塞算法,有些应用程序可能需要自定义的服务质量(QoS)的语义提供最佳体验。
不同的应用需求和众多的TCP优化算法相结合,使得TCP调整和优化算法成为学术和商业研究一个无止境的领域。在本章中,我们只是介绍了影响TCP性能的诸多因素的一些皮毛。还有一些其他机制,如选择性确认(SACK),延迟确认和快速重传以及许多其他机制,这些机制使得TCP会话理解,分析,调整起来更复杂(或有趣的,取决于你的观点)。
虽然说每个算法和反馈机制的具体细节将在后续章节中详细讨论,其核心思想及其影响基本不变:
- TCP三次握手引入了一次完整的往返延迟(RTT)
- 每一个新的连接都有一个慢启动过程
- TCP流量和拥塞控制调节所有连接的吞吐量
- TCP吞吐量受当前拥塞窗口大小影响
其结果是,在现代高带宽网络下,TCP连接的速率通常受限于发送端和接收端之间的传播延迟。此外,虽然带宽的不断增加,但是传播速度基本上限制在光速的一个很小的常数因子上了。在大多数情况下,不是带宽,而是时延,成为TCP的主要瓶颈-参见图2-5 。
作为优化的一个起点,在调整缓冲区设置,几十个TCP超时变量值前,把你的服务器升级到最新版本也许是最简单有效的。TCP控制其性能的最佳实践和底层优化算法在不断发展,这些变化多数包含在最新的内核中。总之,保持你的服务器更新到最新版本,以确保发送端和接收端的TCP连接最佳性能。
从表面上看,服务器内核版本升级似乎是很小也很简单的事情。然而,在实践中,经常会碰到有重大阻力:现有的很多服务器都是基于某个内核版本开发的,许多系统管理员都不愿意冒着风险去执行升级。
一切都是公平的,每一次升级会带来风险,但是,获得更好的TCP性能,这也是一个投资。就看你的去评估了。
如果你的内核已经是最新了,你可以按照下面的最佳实践来调整你的服务器配置:
“增加TCP的初始拥塞窗口(cwnd)” 较大的起点拥塞窗口允许TCP在第一往返传输更多的数据,并可以更快的增长窗口 - 这对那种突发和短请求居多的服务器来说,尤为关键。“慢启动重启动” 对于TCP长链接,禁止空闲后的慢启动,可以提升性能,特别是那种突发性请求居多的场景。“窗口缩放”(RFC 1323) 启用窗口缩放增加最大接收窗口大小,并允许高延迟连接,以实现更好的吞吐量。“TCP快速打开” 允许在某些情况下,在初始的SYN数据包发送应用程序数据。TFO是一种新的优化,这需要客户端和服务器同时支持 -如果你的应用程序有需要,可以考虑。
配合上述的配置和最新的内核可以获得最佳的性能 -更低的延迟和更高的吞吐量。
根据您的应用程序情况,你可能还需要调整其他的TCP服务器上的设置,以优化连接速率,内存消耗,或类似的指标。然而,这些配置设置都依赖于平台,应用程序和硬件 -需要参考平台文档。
对于Linux用户, ss是一个强大的工具,可以用来检查打开的socket各种统计信息。在命令行中,执行“ ss --options--extended --memory --processes --info看到当前的各个端口以及各自的配置。
调整TCP的性能可以为服务端和客户端提供最佳的吞吐量和延迟。然而,应用程序如何使用每一个新的或者已建立TCP连接,对性能也有很大的影响:
- 发送尽量少的数据
- 我们不能让数据跑的更快,但我们能让距离更短
- TCP连接复用是提高性能的关键
消除不必要的数据传输当然是最简单有效的方法 -例如,消除了不必要的资源,或者采用适当的压缩算法确保最小的数据被传输。其次,我们可以通过在离客户端更近的地方部署服务器 -例如,使用一个CDN -将有助于减少网络往返延迟(RTT),并显着提高TCP的性能。最后,在可能的情况下,现有的TCP连接应该被重复使用,以最大限度地减少慢启动和拥塞控制机制所带来的开销。
高性能的TCP连接无论对哪种应用,也无论是哪一个接入到您服务器的连接来说,都是至关重要的。一个简短的checklist:
- 升级到最新版本的服务器内核(Linux系统:3.2 +)
- 确保拥塞窗口(cwnd)大小设置为10 TCP Segments
- 禁用闲置后慢启动
- 确保该窗口缩放启用
- 消除冗余数据传输
- 压缩传输数据
- 在离用户更近的地方部署服务器,以减少往返时间
- 尽可能重用建立的TCP连接