1 时延
对于HOST处理数据报文来看,有如下几种时延:
- 传播延迟: 消息从发送端到接收端需要的时间,是信号传播距离和速度的函数
- 传输延迟: 把消息中的所有比特转移到链路中需要的时间,是消息长度和链路速率的函数
- 处理延迟: 处理分组首部、检查位错误及确定分组目标所需的时间
- 排队延迟: 到来的分组排队等待处理的时间
在TCP连接过程中,有以下几个方面产生的时延是比较大的。
1.1 三次握手产生的时延

每个http连接都需要经过三次握手,从纽约向伦敦请求,启动一次TCP连接,光三次握手至少要花56ms,向伦敦发送分组需要28ms,响应要28ms。可以看出三次握手带来的延迟是非常大的。
1.2 拥塞控制
(1)拥塞崩溃
可能是往返时间超过了所有主机的最大中断间隔,于是相应的主机会产生越来越多的副本,使整个网络陷入瘫痪,最终个交换节点的缓冲区被填满,多出来的分组必须删除。
(2)流量控制
通过缩放接收窗口(rwnd)的大小来控制流量的发送(可配)。

(3)慢启动
通过一个动态可变的拥塞窗口(cwnd)大小来控制流量的发送,网络可发送的最大数据取rwnd(接收窗口)和cwnd(拥塞窗口)的最小值。

如图可见,一个请求需要经过220ms才可以达到最大速率。因为慢启动限制了可用的吞吐量,对于小文件的传输是很不利的。慢启动重启:在连接空闲一段时间后,重置拥塞窗口到一个安全的默认值。毫无疑问,SSR对于长周期空闲而突发请求的TCP连接有很大的影响。

慢启动每次往返都会成倍提高传输的数据量,知道超过接收端的流量控制窗口或者有分组丢失为止。此时拥塞预防算法接入。

(4)带宽延迟积
BDP表示数据链路的容量与其端到端延迟的乘积,结果就是任意时刻在途未确认的最大数据量。发送端和接收端发送超过了未被确认的最大数据量,都会停下来等待对方的ACK,这就造成了数据缺口。为了解决这个问题应该设置窗口足够大,过小的窗口会限制连接的吞吐量。窗口的大小最小应该设置为BDP
(5)队首阻塞
TCP按序交付与可靠交付,如果有时丢包,那么后续的包必须等到这个丢包的数据重发并接收,才能交付给应用程序,这就导致读数据时会感觉延迟交付。在应用程序不关系按序交付和可靠交付的情况下TCP并不是最好的选择。例如音频,丢了一个包可以在音频中插入一个小小的间隙,就可以继续处理后面的包,只要间隙足够小,用户就注意不到,而等待丢包可能导致音频输出产生无法预料的。相对而言,后者的用户体验更差.
2 调优
通过第1部分的描述大致可以知道,TCP的性能主要由如下几个因素决定:
原因
- TCP 三次握手增加了整整一次往返时间;
- TCP 慢启动将被应用到每个新连接;
- TCP 流量及拥塞控制会影响所有连接的吞吐量;
- TCP 的吞吐量由当前拥塞窗口大小控制。
方案
- 把服务器内核升级到最新版本(Linux:3.2+);
- 确保 cwnd 大小为 10;
- 禁用空闲后的慢启动;
- 确保启动窗口缩放;
- 减少传输冗余数据;
- 压缩要传输的数据;
- 把服务器放到离用户近的地方以减少往返时间;
- 尽最大可能重用已经建立的 TCP 连接。
3 从TCP的实现机理方面来看性能提高措施
3.1 滑动窗口
在确认应答机制中,接收方每接收到一个数据段,都要给发送方发送一个ACK应答报文,发送方在接收到应答报文后才继续发送下一个报文段,这样可保证数据传送的可靠性。但是这样做性能较差,尤其在数据往返时间较长的时候。 TCP中引入了滑动窗口机制,只要数据处于这个滑动窗口中,就可以在上一个数据段未收到确认时依然将后面的数据发送出去。这样就可以一次发送多条数据,就大大的提高了性能(其实是将多个段的等待确认时间重叠在了一起)。
采用滑动窗口方式发送数据的过程如下:

滑动窗口大小:指无需等待确认应答而可以继续发送发送数据的最大值。上图中的滑动窗口大小为4000个byte(即四个数据段)。
发送前四个段时无需等待任何ACK报文,直接连续发送;收到第一个ACK后,窗口向后移动一个段,发送第五个段,之后以此类推;操作系统为了维护这个滑动窗口,需要开辟一个发送缓冲区,其关系如下:

只有确认过的数据才能从缓冲区删掉。发送窗口工作过程:

当然也存在着接收窗口与接收缓存:

连接双方的接收窗口与发送窗口越大,则网络吞吐量越高。
3.2 快重传
无论何种情况都可能会产生丢包问题,那么这里没有经过确认就批量发送报文段如果发生丢包问题该如何解决呢?这里分两种情况讨论。
3.2.1 在数据发送过程中产生丢包问题
这种情况下报文段没有成功传送到接收方,而因为有滑动窗口机制,所以发送方会继续发送后续报文段。但是接收方每次收到报文都只会对其收到的最后一个“有序”报文段进行确认,这样发送方就会不断地发送被丢失报文段后面的数据段,接收方不断发送对到达的“有序”报文段的最后一个报文段的确认报文,当发送方收到3个同样的确认应答时就进行重发。其过程如下:

3.2.2 应答报文丢失
接收方发送出的ACK报文也可能会在中途丢失,这样发送方就可能收不到前面发送的数据的确认报文,但是如果收到了后续报文段的ACK也会认为前面的报文段已经被接收方收到,这样就进行了确认。其过程为:

这种机制就叫做“高速重发控制”(也叫快重传)。
3.2.3 延迟应答
我们都知道,窗口越大,网络吞吐量就越大,传输效率越大,在保证网络不拥塞的情况下应尽量提高传输效率。 接收方在收到数据后,会对发送方发出应答报文ACK,现在假想这种情况: 假设接收缓冲区为1M,一次收到了500K数据;如果立即应答,那么返回的窗口就是500K。但实际上接收方处理接收窗口中数据的速度会很快,10ms内就可以把500K数据从缓冲区取出。这种情况下,很可能接收方还没有接收到下一个报文段缓冲区就又增大了,所以即使下一个报文段大于500K,接收缓冲区也能成功接收。如果接收方接收到第一个报文段后不立即返回,而是等待一会儿(比如再等200ms)再应答,那么返回的窗口大小就有1M。 这就是延迟应答。延迟应答的”延迟“限制:
- 数量限制:每隔N个包就应答一次。
- 时间限制:超过最大延迟时间就应答一次。
具体的数量和超时时间,依操作系统不同也有差异,一般N取2,超时时间取200ms。其过程如下:

延迟确认应答是能够提高网络利用率从而降低计算机处理负荷的一种较优的处理机制。
3.2.4 捎带应答
根据应用层协议,发送出去的消息到达对端,对端进行处理以后,会返回一个回执。 例如,电子邮件协议的SMTP或POP、文件传输协议FTP中的连接控制部分等。 所以,TCP的确认和应用端的回执数据就被放到了一个数据包内,这种方式就叫捎带应答。如下图:

捎带应答需要注意下面几点:
- 接收数据之后,如果立刻返回确认应答,就无法实现捎带应答。也就是说,如果没有启用延迟确认应答就无法实现捎带应答。延迟确认应答是能够提高网络利用率从而降低计算机处理负荷的一种较优的处理机制;
- 正是因为延迟确认和捎带应答机制,让TCP断开连接的时候四次挥手有时候变成三次挥手。因为,如果在TCP断开连接的时候,有时候只能够抓取3个数据包。这三个数据包为客户端的FIN、服务器的FIN和ACK<由于捎带应答,这时server端的FIN报文(请求断开连接)和ACK报文(第一次client端发的FIN报文请求报文进行确认)合成了一个请求并确认报文>、客户端的ACK;