影响TCP 网络时延的因素
硬件速度
网络和服务器的负载
请求和响应报文的尺寸
客户端和服务器之间的距离
TCP 协议的技术复杂性
TCP协议产生的时延
TCP 连接建立握手;
TCP 慢启动拥塞控制;
数据聚集的 Nagle 算法;
用于捎带确认的 TCP 延迟确认算法;
TIME_WAIT 时延和端口耗尽。
TCP连接建立
TCP连接的建立,需要经历3个报文的交互过程,沟通相关连接参数,这个过程称为三次握手(three-way handshake)。
因此,如果在每次发送数据之前,都重新建立一次TCP连接,那么建立连接的耗时将对性能产生较大的影响(特别是在发送少量数据的情况下)。
三次握手四次挥手(参考自coolshell)
优化方法
建立长连接,多次数据的发送复用同一条连接。
TCP慢启动
如果在发送方和接收方之间存在多个路由器和速率较慢的链路,此时多个发送方一开始便向网络发送多个报文段,由于受网络传输和服务端处理能力的影响,一些中间路由器必须缓存分组,并有可能最终耗尽存储器的空间,因而更多的报文发送将使网络出现拥塞。
TCP慢启动(slow start),就是用于防止因特网的突然过载和拥塞的一种流量控制机制。
慢启动为发送方的TCP增加了一个窗口:拥塞窗口(congestion window),简称cwnd。
刚建立连接时,拥塞窗口被初始化为1个报文段。每收到一个ACK,拥塞窗口就增加一个报文段。发送方取拥塞窗口与接收方通告窗口中的最小值作为发送上限。
也就是说,TCP连接会随着时间进行自我“调谐”,起初会限制连接的最大速度,如果数据成功传输,会随着时间的推移提高传输的速度。
注:拥塞窗口是发送方使用的流量控制,而通告窗口则是接收方使用的流量控制。
优化方法
采用长连接,避免每次建立连接后的慢启动。
Nagle算法
在广域网上,小分组会增加网络拥塞出现的可能性。Nagle算法(根据其发明者John Nagle命名)旨在收集这些小分组,以一个分组的方式发出去,以提高网络效率。
该算法要求一个TCP连接上最多只能有一个未被确认的未完成的小分组,在该分组的确认到达之前不能发送其他的小分组。
该算法的优越之处在于它是自适应的:确认到达得越快,数据也就发送得越快。
Nagle 算法会引发以下性能问题
当报文无法填满一个分组时,需要等待其他额外数据;
Nagle算法会阻止数据的发送,直到有确认分组抵达为止,但确认分组自身会被延迟确认算法延迟 100 ~ 200 毫秒。
算法伪代码
优化方法
对于实时性要求较高的应用场景,可以通过设置TCP_NODELAY参数来关闭Nagle算法,提高性能。
延时确认算法
通常TCP在接收到数据时并不立即发送ACK;相反,它推迟发送,以便将ACK与需要沿该方向发送的数据一起发送。
有时称这种现象为数据捎带ACK,由于确认报文通常很小,所以TCP允许在发往相同方向的输出数据分组中对其进行“捎带”。
绝大多数实现采用的时延为200ms,也就是说,TCP将以最大200ms的时延等待是否有数据一起发送。
通常,延迟确认算法会引入相当大的时延。
优化方法
根据所使用操作系统的不同,可以调整或禁止延迟确认算法。(这个方法我没尝试过)
TIME_WAIT״̬
TIME_WAIT状态也称为2MSL等待状态。
当某个 TCP 端点关闭 TCP 连接时, 会在内存中维护一个小的控制块,用来记录最近所关闭连接的 IP 地址和端口号。
这类信息只会维持一小段时间,通常是所估计的报文段最大生存时间的的两倍(称为2MSL,通常为2分钟左右),以确保在这段时间内不会创建具有相同地址和端口号的新连接。
实际上,这个算法可以防止在两分钟内创建、关闭并重新创建两个具有相同IP地址和端口号的连接。
将 2MSL 的值取为 2 分钟是有历史原因的。很早以前,路由器的速度还很慢,人们估计,在将一个分组的复制副本丢弃之前,它可以在因特网队列中保留最多一分钟的时间。现在,最大分段生存期要小得多了。
报文段最大生存时间MSL(Maximum Segment Lifetime),是指任何报文段被丢弃前在网络中的最长生存时间。
RFC 793 [Postel 1981c]指出MSL为2分钟。然而,实现中的常用值是30秒,1分钟或2分钟。
优化方法
打开tcp_tw_reuse,让程序可以重用处于TIME_WAIT状态的端口。如果使用tcp_tw_reuse,必需设置tcp_timestamps=1(默认值)。(这个对于快速重启某些服务很有用,特别是服务端程序)
打开tcp_tw_recycle,让处于TIME_WAIT状态的套接字更快的回收。
贴一个nagle算法更详细的讲解
Nagle算法用于对缓冲区内的一定数量的消息进行自动连接。该处理过程(称为Nagling),通过减少必须发送的封包的数量,提高了网络应用程序系统的效率。
2)如果该包含有FIN,则允许发送;
3)设置了TCP_NODELAY选项,则允许发送;
4)未设置TCP_CORK选项时,若所有发出去的包均被确认,或所有发出去的小数据包(包长度小于MSS)均被确认,则允许发送。
1)缓冲区中的字节数达到了一定量;
2)等待了一定的时间(一般的Nagle算法都是等待200ms);
3)紧急数据发送。
总结:
1)打开TCP_NODELAY选项,则意味着无论数据包是多么的小,都立即发送(不考虑拥塞窗口)。