TCP 负责在不可靠的传输信道之上提供可靠的抽象层,向应用层隐藏了大多数网络通信的复杂性能,比如丢包重发、按需发送、拥塞控制及避免、数据完整,等等。采用 TCP 数据流可以确保发送的所有字节能够完整地被接收到,而且客户端的顺序也一样。
但是 TCP 设计并未过多顾及时间,由此给浏览器 Web 性能带来了挑战。
所有 TCP 连接一开始都必须经过三次握手。客户端与服务器在交换应用数据之前,必须就起始分组序列号,以及其他一些连接相关的细节达成一致。处于安全考虑,序列号由两端随机生成。
客户端可以在发送 ACK 分组之后立即发送数据,而服务器必须等接收到 ACK 分组之后发送数据。
每个 TCP 连接都要经过三次握手,倘若客户端与服务器距离过长,会造成非常大的性能影响。因而,提升 TCP 性能关键在于想办法重用连接。
为解决这个问题,人们在积极寻找各种方案,其中长链接(Keep-Alive)、负载均衡、TFO(tcp fast open)便是其中的一些解决办法。
Keep-Alive,HTTP 1.1 之后默认开启,指在一个 TCP 连接中可以持续发送多份数据而不会断开连接。
基本原理:客户端(如:ClientA)与负载均衡设备之间进行三次握手并发送 HTTP 请求。负载均衡设备收到请求后,会检测服务器是否存在空闲的长链接,如果不存在,服务器将建立一个新连接。当 HTTP 请求响应完成后,客户端与负载均衡设备协商关闭连接,而负载均衡则保持与服务器之间的这个连接。当有其他客户端(如:ClientB)需要发送 HTTP 请求时,负载均衡设备会直接向服务器之间保持的这个空闲连接发送 HTTP 请求,避免来由于新建 TCP 连接造成的延时和服务器资源耗费。
TCP 连接复用
尽管开启了长链接,可是依然有35%的请求是重新发起一条连接,而握手会造成一定的延迟,TFO 的目标就是为了去除这个延迟,在三次握手期间也能交换数据。
基本原理:
TFO
拥塞:即对供不应求,对资源的需求超过了可用的资源,网络性能下降,整个网络的吞吐量随之负荷的增大而减小,甚至会发生拥塞崩溃的现象。
为了减缓网络拥塞现象,TCP 加入许多机制用来控制双向发送数据的速度。如流量监控、拥塞控制、拥塞预防机制等。
流量控制是一种预防发送端过多向接收端发送数据的机制。
滑动窗口是实现流量控制的一种方法,一个简单例子:
设 A 向 B 发送数据。在建立连接时,B 告诉了 A:“我的接收窗口值 rwnd = 400“ (rwnd: receiver window),因此,发送方的发送窗口不能超过接收方给出的接收窗口的数值。TCP 窗口的单位时字节,并不是报文段。设每个报文段的字节长 100,而数据报文段序号的初始值为 1,大写 ACK 表示首部中的确认位 ACK,小写 ack 表示确认字段的值 ack。
从图中可以看出,B 进行了三次流量控制。第一次把窗口减少到 rwnd = 300,第二次又减少到了 rwnd = 100,最后减到 rwnd = 0,即不允许发送数据了。
当 rwnd = 0 时,则意味着必须由应用层先清空缓存区,才能接收剩余数据。这个过程贯穿于每个 TCP 连接的整个生命周期:每个 ACK 分组都会携带相应的最新的 rwnd 值,以便两端动态调整数据流,使之适应发送端和接收段的容量及处理能力。
尽管流量监控可以防止发送端向接收端过多发送数据,但是发送端和接收端在连接建立之初,并不知道可用带宽是多少,因此需要一个估算机制,然后还可以根据网络中不断变化的条件而动态改变速度。
拥塞控制:防止过多的数据注入到网络中,这样可以使网络中的路由器或链路不致于过载。
慢启动是实现拥塞控制的一种方法,此外还有拥塞预防、快速重发和快速恢复。
慢启动,即是在分组被确定以后,增大窗口大小,慢慢启动。
具体实现如下:
由于慢启动的设计,限制了可用的吞吐量。对于大型流式下载服务的影响倒不显著,但是对于小文件的传输却非常不利,常常会出现还没有达到最大窗口请求就被终止的情况。
简单演示三次握手与慢启动对简单 HTTP 传输的影响。
连接参数:
tcp 连接取得文件
再一次发送
慢启用使用 cwnd 作为起始值发送数据量,随后成倍增长。直到超过接收系统配置的拥塞阈值(ssthresh)窗口,或者发生分组丢失现象,此时拥塞预防算法介入。
由于已经发生拥堵,必须采取删包措施。需要重新调整 cwnd 大小,此后拥塞预防按照自己的算法来增大 cwnd 以避免丢包。若再次丢包,则从头开始。