Tcp Transmission Control Protocol

Review

  1. 2024-10-29 22:11

[!Summary]

一、Introduction #

TCP在两端(通常指浏览器和Web服务器)之间创建一个连接,然后处理消息传递,并确保消息到达。当消息丢失时处理重传,并确保消息在传递给应用层(如HTTP)之前是有序的。

TCP给每个TCP数据包分配一个序列号,如果数据包在到达时顺序不对,则进行重排;如果丢失了部分数据包,则根据序列号来重新请求。

TCP运行的基本方式会导致5个主要的问题,它们至少影响到了HTTP:

  1. 有一个连接创建的延迟。要在连接开始时协商发送方和接收方可以使用的序列号。
  2. TCP慢启动算法限制了TCP的性能,它小心翼翼地处理发送的数据量,以尽可能防止重传。
  3. 不充分使用连接会导致限流阈值降低:如果连接未被充分使用,TCP会将拥塞窗口的大小减小,因为它不确定在上个最优的拥塞窗口之后网络参数有没有发生变化。
  4. 丢包也会导致TCP的限流阈值降低:TCP认为所有的丢包都是由窗口拥堵造成的,但其实并不是。
  5. 数据包可能被排队:乱序接收到的数据包会被排队,以保证数据是有序的。

TCP慢启动机制可以感知TCP在网络上的最佳吞吐量,以免过大冲垮或者危害到网络。TCP采用很谨慎的算法,它以低速率启动并增大到最大速率,在此过程中它会仔细监控连接和数据发送速度以保证能处理所有数据。

一个TCP连接可以发送的数据量取决于拥塞窗口的大小。拥塞窗口开始时很小(过去通常是4个),对于现代的PC和服务器,开始时发送10个数据包(相当新的变化,很多服务器还使用之前的4个),使用的最大报文长度(MSS)为1460字节,也就是14KB。在慢启动期间,每次往返,拥塞窗口的大小翻倍。当达到最大容量之后,如果没有发生丢包,TCP拥塞控制就进入拥塞避免阶段,随后拥塞窗口还会持续增长,但会变成慢得多的线性增长(不同于慢启动期间的指数级增长),直到它开始看到丢包,认为到了最大容量。

因为TCP慢启动的指数增长特性,所以按大多数定义来说它并不慢。实际上,TCP的拥塞避免阶段的增长更慢。

有一个经常被人吹捧的Web性能优化建议,是将所有的关键资源放到HTML的前14KB中。这个理论来自于,前14KB会在TCP的前10个数据包中加载,这样可以避免TCP确认消息的延迟。将关键资源放到HTML的开始处还是有必要的,但现在看来,在HTTPS或者HTTP/2下,不需要严格要求14KB以内。

连接闲置降低性能 #

在连接刚启动时和连接闲置时,TCP慢启动算法会导致延迟。TCP比较小心谨慎,在闲置一段时间后,网络情况可能发生变化,所以TCP将拥塞窗口大小降低,重新进行慢启动流程,以再次找到最佳的拥塞窗口大小。

丢包降低TCP性能 #

TCP还把丢包当成极端事件。它认为这个事件是由容量限制造成的,因而它会做出激烈反应,直接将拥塞窗口大小减半,也就是说会将容量减半(具体取决于所使用的TCP拥塞控制算法)。然后TCP使用拥塞避免算法再次计算速度,并进入拥塞避免阶段。认为丢包完全是由拥堵造成的,然后大幅降低网速,这是不正确的。

丢包会导致数据排队 #
TCP确认(丢包重传机制) #
  1. 累计确认:
  2. SACK (Selective Acknowledgement) 选择性确认,可以不按照顺序确认报文。

优化TCP #

由于多路复用,HTTP队首阻塞在HTTP/2中已经不是一个问题了,但是TCP的队头阻塞却成了问题,特别是在容易丢包的环境下。

  1. 提高初始拥塞窗口大小:TCP慢启动需要一次往返来提升拥塞窗口大小,最早的时候,初始的拥塞窗口大小是1个TCP数据包,几年后这个初始的设置值变为2,然后提升到4,到了Linux内核2.6.39,这个设置值从4增加到了10。这个设置值通常被写死到内核代码中,所以除非升级操作系统,否则不建议修改。
  2. 支持窗口缩放:在传统情况下,TCP所允许的最大拥塞窗口大小是65535字节,但新版本中添加了缩放因子,理论上允许拥塞窗口最大到1GB。
  3. 使用SACK(Selective Acknowledgment,选择性响应):响应乱序的数据包,以避免丢包时重传。比如发送了包1~10,但丢掉了包4,可以响应1~3和5~10。这时,只有包4需要重传。如果没有这个功能,则需要重传包4~10。
  4. 禁止重启慢启动:闲置一段时间之后,TCP连接的网速会降回去。
  5. 使用TFO(TCP Fast Open,TCP快速打开)
  6. 使用拥塞控制算法PRR和BBR
  7. MPTCP
TFO #

在传统的TCP实现中,必须经过3次握手才能发送数据,为了尽快发送数据,RFC 7413 定义了 TFO。

TFO(TCP Fast Open,TCP快速打开)允许使用TCP三次握手的初始SYN部分发送初始数据包。可以使用这种方法避免与TCP相关的连接创建延迟。出于安全的原因,这个数据包只能在TCP重连时使用,而不能在初次连接时使用,它同时需要客户端和服务端的支持。

TFO带来的提升真的很显著。Google曾经表示:“通过对网络流量的分析和网络仿真,我们得出TFO能够将HTTP网络延迟降低15%,网页整页加载时间平均降低10%,有时候能降低40%。”

TFO过程 #

➀ 首次建立TCP连接时,客户端在发送SYN的同时携带了Fast Open 选项,其中 Cookie 为空,这表明客户端请求服务器提供 Cookie;服务器将 Cookie 发送给客户端。

➁ 重新连接时,客户端在发送SYN的同时在 Fast Open 选项中携带了之前服务器提供的 Cookie 的数据;服务器验证 Cookie 通过后,接收携带的数据。

拥塞控制算法 #

PRR(Proportional Rate Reduction,按比例降低,从Linux 3.2版本之后成为默认算法)是对CUBIC的增强,当丢包时它减小拥塞窗口,但减小的值不到一半。

BBR(Bottleneck Bandwidth and Round-trip propagation time,瓶颈带宽和往返时间),已经有数据表明它可以大幅度提升性能,特别是对于HTTP/2连接。

MPTCP #

改变本地IP地址会导致TCP重新建立连接,而当今移动终端越来越多,需要能够在网络之间无缝切换。解决这个问题的方案是利用MPTCP(MultiPath TCP,多路TCP),标准见RFC 6824。另外,MPTCP也被用于利用多个信道增加传输速率。

Reference #