3.1. 快链路
我们需要有一条(相对)快速、(相对)顺畅、(相对)稳定的网络通道承载业务数据的传输,这条路的最好是传输快、不拥堵、带宽大、收费少。生活中做个类比,我们计划驱车从深圳到广州,如果想当然走广深高速十之八九要杯具,首先这个高速略显破败更像省道,路况不佳不敢提速;其次这条路上的车时常如过江之鲫,如果身材不好操控不便,根本就快不起来;最后双向六车道虽然勉强可以接受,但收费居然比广深沿江高速双向八车道还贵;正确的选路方案目前看是走沿江高速,虽然可能要多跑一段里程,但是通行更畅快。实际上,真实情况要更复杂,就如同【图二 有线互联网和移动互联网网络质量差异】所示,漫漫征途中常常会在高速、国道、省道、田间小道上切换。
如何才能做到快链路,且听下面分解。
3.1.1. TCP/IP协议栈参数调优
纯技术活,直接上建议得了,每个子项争取能大致有个背景交待,如果没说清楚,可以找Google。
① 控制传输包大小
控制传输包的大小在1400字节以下。暂时不讲为什么这样建议,先举个例子来类比一下,比如一辆大卡车满载肥猪正在高速上赶路,猪笼高高层叠好不壮观,这时前方突然出现一个隧道限高标识,司机发现卡车超限了,这下咋整。方案一,停车调头重新找路,而且十之八九找不到,最后只能哪来回哪;方案二,把其中一群猪卸下来放本地找人代养,到达目的地卸完货回来再取,你别说,这个机制在TCP/IP协议栈中也有,学名“IP分片”,后面会专门介绍。这个故事侧面证实美国计算机科学家也曾经蹲在高速路边观察生猪超载运输的过程,并饱受启发。且慢,每次遇到问题,想到一些方案后我们都应该再扪心自问:“还有没有更好的办法呢?”。当然有,参照最近流行的说法,找个台风眼,把猪都赶过去,飞一会就到了,此情此景想想也是醉了。
回归正题,概括的说,我们设定1400这个阈值,目的是减少往复,提高效能。因为TCP/IP网络中也有类似高速限高的规定,如果在超限时想要继续顺畅传输,要么做IP分片要么把应用数据拆分为多个数据报文(意指因为应用层客户端或服务器向对端发送的请求或响应数据太大时,TCP/IP协议栈控制机制自动将其拆分为若干独立数据报文发送的情况,后面为简化讨论,都以IP分片这个分支为代表,相关过程分析和结论归纳对二者均适用)。而一旦一个数据报文发生了IP分片,便会在数据链路层引入多次的传输和确认,加上报文的拆分和拼接开销,令得整个数据包的发送时延大大增加,并且,IP分片机制中,任何一个分片出现丢失时还会带来整个IP数据报文从最初的发起端重传的消耗。有点枯燥了,我们从一些基础概念开始逐步深入理解:
a. 【以太网】
这个术语一般是指数字设备公司(Digital Equipment Corp.)、英特尔公司(I n t e l Corp .)和X e r o x公司在1 9 8 2年联合公布的一个标准,它是当今TCP/IP采用的主要网络技术。以太网采用一种称作C S M A / C D的媒体接入方法,其意思是带冲突检测的载波侦听多路接入(Carrier Sense, Multiple Access with Collision Detection)。随着以太网技术的不断演进,传输速率已由最初的10 Mb/s发展到如今100Mb/s、1000Mb/s、10000Mb/s等。
我们现在使用的TCP/IP网络协议,基本上都在以太网上传输,数据被封装在一个个以太网包中传递,这些以太网包就是那一辆辆运猪的大卡车。以太网包的封装格式可以参考【图三 以太网的封装格式(RFC 894)】,很容易看出以太网包能传输的有效“数据”大小在46 ~ 1500字节之间。如果我们把以太网看做是运猪的高速公路,能承载有效数据的最大值看作是高速路上隧道的限高,那么这个限高在TCP/IP协议中学名是MTU(Maximum Transmission Unit,最大传输单元)。MTU属于链路层制定的逻辑(并非物理)特性限制,所谓无规矩不成方圆。
【图三 以太网的封装格式(RFC 894)】
b. 【TCP/IP数据报】
TCP/IP数据报被封装在以太网包的“数据”中,通过【图四 TCP数据在IP数据报中的封装】可以看到,一个IP数据报包括IP包头、TCP包头和TCP数据三个部分,其中两个包头分别用于IP层和TCP层的报文传输控制,可以理解为运猪的大卡车和猪笼。TCP数据则是有效载荷,可以理解为那群肥猪。
【图四 TCP数据在IP数据报中的封装】
我们再来详细看看IP数据报,如【图五 IP数据报格式及首部中的各字段】所示,一个标准IP数据报中,IP包头大小为20字节,如果加上可选项,则IP包头最大可以达到60字节。
【图五 IP数据报格式及首部中的各字段】
TCP数据报如【图六 TCP数据报格式及首部中的各字段】所示,一个标准TCP包头大小为20字节,如果加上可选项,则最大也可以达到60字节。
【图六 TCP数据报格式及首部中的各字段】
c. 【TCP MSS】
TCP MSS(TCP Maximum Segment Size,TCP最大报文段长度,后面均简称MSS)表示TCP/IP协议栈一次可以传往另一端的最大TCP数据长度,注意这个长度是指TCP报文中的有效“数据”(即应用层发出的业务数据)部分,它不包括TCP报文包头部分,我们可以把它理解为卡车能装运生猪的最大数量或重量。它是TCP选项中最经常出现,也是最早出现的选项,占4字节空间。
MSS是在建立TCP链接的三次握手过程中协商的,每一方都会在SYN或SYN/ACK数据报文中通告其期望接收数据报文的MSS(MSS也只能出现在SYN或SYN/ACK数据报中),说是协商,其实也没太多回旋的余地,原因一会讲。如果协商过程中一方不接受另一方的MSS值,则TCP/IP协议栈会选择使用默认值:536字节。
有了以上的基础知识,我们就能比较清晰的描述出以太网、MTU、TCP/IP数据报文和MSS之间的关系了,如【图七 TCP/IP数据报、MTU/MSS在以太网格式中的关系】所示,MTU和MSS关系用公式表达就是:
MTU = IP包头 + TCP包头 + MSS;
对照到我们肥猪装运的例子,自然得出公式如下:
限高 = 卡车高度 + 笼子高度 + 生猪数量或重量;
【图七 TCP/IP数据报、MTU/MSS在以太网格式中的关系】
注:FCS(Frame Check Sequence)是指帧校验值;
实际上MSS值太小或太大都不合适。
太小比如设为1字节,那么为了传输1个字节的数据,得搭上IP包头的20字节和TCP包头的20字节,如果再加上链路层、物理层的其它开销,显然效率低下不够环保,这就如同卡车跑一趟只拉一头肥猪一样,相当坑。
MSS是不是越大越好呢,这也符合我们的正常思维逻辑,就好比养猪场和买家都希望卡车一趟能多运几头肥猪,可以加快资源周转效率。但实际情况是MSS如果设得太大,封装的数据过多,不但传输时延会增加,还很可能因为超过MTU的限制,使得在IP层传输过程中发生分片(又是它,忍着,马上就会展开了),接受方在处理IP分片包所消耗的资源和处理时间都会增大,前面也提到过,如果IP分片在传输中出现分片丢失,哪怕只是丢失一个分片,都会引起整个IP数据报的重传,这是因为IP层本身没有设计超时重传机制,有兴趣可以研读《TCP/IP详解 卷一:协议》了解详细细节。由此可以想见网络开销会因此大大增加。
TCP/IP协议设计者是不希望分片出现的,现在有点明白前面说MSS协商回旋余地不大的含义了吧。另外,MSS同滑动窗口和拥塞控制也有关联,后续谈到相关话题时我们再细聊。
d. 【IP分片】
快乐运猪路遇限高紧急应对方案二闪亮登场,IP数据报文传输过程中,任何传输路径上节点的IP层在接收到一份要发送的IP数据报文时,首先会通过路由选路判断应从本地哪个网络接口把IP数据报转发出去,随后查询获取该网络接口的MTU,如果IP数据报文长度超过了这个MTU,且该数据报文没有设置DF(Don't Frament,不要分片,非缺省值)标志位,就得做IP分片,即把接收到的IP数据报文拆分成多个更小(不超过该接口MTU)的IP数据报文继续传输,并且,分片的数据可能在路上会被再次分片,分片到达最终目的地后会按顺序重新组装还原,【图五 IP数据报格式及首部中的各字段】中3位标志和13位片偏移就是用来干这个的。
为了避免IP分片,TCP/IP协议设计者在TCP层实现了MSS协商机制,设想如果最终确定的MSS小于路由路径中最小的那个MTU,那么就能避免IP分片的发生。
在TCP链接三次握手过程中,网络通讯的两个端点在SYN和SYN/ACK数据报文中分别把自己出口MSS发给对端,以便对方了解自己的“限高”水平,最终控制发出的应用数据报文大小,达到避免IP分片的目的。
如果运气好,路由路径上的路由设备会积极参与三次握手过程中MSS协商机制,一旦发现自己出口的MSS比数据报文中的那个小,就会主动修改数据报文中的MSS,这样整个路由链路端到端这条“高速路”的整体“限高”水平就准确清晰了。
通过【图八 TCP MSS协商过程】,可以了解上述TCP MSS的协商过程。注意,这个“完美”方案需要运气好才行。因为中间路由设备五花八门,不能支持或者不愿支持MSS协商的情况时有发生。想让大伙都积极支持协商的美好愿望,就如同满怀对全世界各国政府官员实施财产公示的期许,结果是一样一样的。
【图八 TCP MSS协商过程】
快乐运猪路遇限高紧急应对方案一有没有发挥空间呢?很好的问题,聪明的TCP/IP协议设计者当然不甘心,于是利用前面提到的DF标志位设计了一个叫做路径MTU发现的机制就用到了方案一的原理,如果IP数据报文的3位标志字段中的DF位置为1,则IP层遇到需要IP分片时,就会选择直接丢弃报文,并返回一个相应的ICMP出错报文,看到了吧,此路不通,请带领群猪原路返回。这个方案运作成本颇高。不继续深入描述了,有兴趣可以研读《TCP/IP详解 卷一:协议》。
至此,我们可以得出如下结论,TCP/IP数据报文大小超过物理网络层的限制时,会引发IP分片,从而增加时空开销。
因此,设定合理的MSS至关重要,对于以太网MSS值建议是1400字节。什么,你的数学是体育老师教的吗?前面说以太网最大的传输数据大小是1500字节,IP数据报文包头是20字节,TCP报文包头是20字节,算出来MSS怎么也得是1460字节呀。如果回答是因为很多路由设备比如CISCO路由器把MSS设定为1400字节,大伙肯定不干,回忆一下IP和TCP的数据报包头都各有40字节的可选项,MTU中还需要为这些可选项留出空间,也就压缩了MSS的空间。要是再追问为啥这个值不是1380字节,那就有点过分了。
那么问题来了,控制“限高”哪种方案才最强。我们尝试探讨一下。