HTTP之对TCP性能的考虑
TCP 相关时延如下:
- TCP 连接建立握手;
- TCP 慢启动拥塞控制;
- 数据聚集的 Nagle 算法;
- 用于捎带确认的 TCP 延迟确认算法;
- TIME_WAIT 时延和端口耗尽。
1. TCP 连接的握手时延
建立一条新的 TCP 连接时,服务器与客户端需要进行三次握手。如果连接只用来传送少量数据,这些交换过程就会严重降低 HTTP 的性能。
2. 延迟确认
由于因特网自身无法确保可靠的分组传输(因特网路由器超负荷的话,可以随意丢弃分组),所以 TCP 实现了自己的确认机制来确保数据的成功传输。
每个 TCP 段都有一个序列号和数据完整性校验和。每个段的接收者收到完好的段时,都会向发送者回送小的确认分组。如果发送者没有在指定的窗口时间内收到确认信息,发送者就认为分组已经被破坏或损毁,并重发数据。
由于确认报文分销,所以 TCP 允许在发往相同方向的输出数据分组中对其进行 "捎带"。TCP 将返回的确认信息与输出的数据分组结合在一起,可以更有效地利用网络。为了增加确认报文找打同向传输数据分组的可能性,很多 TCP 栈都实现了一种 "延迟确认" 算法。延迟确认算法会在一个特定的窗口时间(通常是 100 ~ 200 毫秒)内将输出确认存放在缓冲区中,以寻找能够捎带它的输出数据分组。如果在那个时间段内没有输出数据分组,就将确认信息放在单独的分组中传送。
3. TCP 慢启动
TCP 数据传输的性能还取决于 TCP 连接的使用期(age)。TCP 连接会随着时间进行自我 "调谐",起初会限制连接的最大速度,如果数据成功传输,会随着时间的推移提高传输的速度。这种调谐被称为 TCP 慢启动(slow start),用于放置因特网的突然过载和拥塞。
TCP 慢启动限制了一个 TCP 端点在任意时刻可以传输的分组数。简单来说,每成功接收一个分组,发送端就有了发送另外两个分组的权限。如果某个 HTTP 事务有大量数据要发送,是不能一次将所有分组都发送出去的。必须发送一个分组,等待确认;然后可以发送两个分组,每个分组都必须被确认,这样就可以发送四个分组了,以此类推。这种方式被称为 "打开拥塞窗口"。
由于存在这种拥塞控制特性,所以新连接的传输速度会比已经交换过一定量数据的、"已调谐" 连接慢一些。由于已调谐连接更快一些,因此 HTTP 中有一些可以重用现存连接的工具,如 HTTP 的 "持久连接"。
4. Nagle 算法与 TCP_NODELAY
TCP 有一个数据流接口,应用程序可以通过它将任意尺寸的数据放入 TCP 栈中--即使一次只放一个字节也可以。但是,每个 TCP 段中都至少装载了 40 个字节的标记和首部,所以如果 TCP 发送了大量包含少量数据的分组,网络的性能就会严重下降。
Nagle 算法试图在发送一个分组之前,将大量 TCP 数据绑定在一起,以提高网络效率。
Nagle 算法鼓励发送全尺寸(LAN 上最大尺寸的分组大约时 1500 字节,在因特网上是几百字节)的段。只有当所有其他分组都被确认之后,Nagle 算法才允许发送非全尺寸的分组。如果其他分组仍然在传输过程中,就将那部分数据缓存起来。只有当挂起分组被确认,或者缓存中积累了足够发送一个全尺寸分组的数据时,才会将缓存的数据发送出去。
Nagle 算法会引发下列问题:
- 小的 HTTP 报文可能无法填满一个分组,可能会因为等待哪些永远不会到来的额外数据而产生时延。
- Nagle 算法与延迟确认之间的交互存在问题--Nagle 算法会阻止数据的发送,直到有确认分组抵达为止,但确认分组自身会被延迟算法延迟 100~200 毫秒。
HTTP 应用程序常在自己的栈中设置参数 TCP_NODELAY,禁用 Nagle 算法,提高性能。如果这样做,一定要确保会向 TCP 写入大块的数据,这样就不会产生一堆小分组。
5. TIME_WAIT 累积与端口耗尽
当某个 TCP 端点关闭 TCP 连接时,会在内存中维护一个小的控制块,用来记录最近所关闭连接的 IP 地址和端口号。这类信息只会维持一小段时间,通常是所估计的最大分段使用期的两倍(称为 2MSL,通常为 2 分钟)左右,以确保在这段时间内不会创建具有相同地址和端口号的新连接。实际上,这个算法可以防止在两分钟内创建、关闭并重新创建两个具有相同 IP 地址和端口号的连接。

浙公网安备 33010602011771号