队头阻塞其实有两种,一种是 TCP 队头阻塞,另一种是 HTTP 队头阻塞,而这两者之前其实还存在一定的联系,毕竟 HTTP 是建立在 TCP 协议之上的应用层协议

1 TCP队头阻塞

TCP 是面向连接的、可靠的流协议,其为上层应用提供了可靠的传输,保证将数据有序并且准确地发送至接收端
为了做到这一点,TCP采用了“序号”和“重传”机制,另外还使用“流量控制”和“拥塞控制”来提高网络利用率。

应用层(如HTTP)发送的数据会先传递给传输层(TCP),TCP 收到数据后并不会直接发送,而是先把数据切割成 MSS 大小的包,再按窗口大小将多个包丢给网络层(IP 协议)处理
image.png

IP 层的作用是“实现终端节点之间的通信”,并不保证数据的可靠性和有序性,所以**接收端可能会先收到接收窗口末端的数据,这个时候 TCP 是不会向上层应用交付数据的,它得等到前面的数据都接收到了才向上交付,所以这就出现了队头阻塞,即

当然 TCP 有快重传快恢复机制,一旦收到失序的报文段就立即发出重复确认,并且接收端在连续收到三个重复确认时,就会把慢开始门限减半,然后执行拥塞避免算法,以快速重发丢失的报文。

除了队头阻塞会影响传输速度,TCP 的三次握手四次挥手以及延迟确认应答Nagle算法等也会带来一定的延迟。

2 HTTP队头阻塞

HTTP 有多个版本,这里要分开讨论。

1 HTTP/1.0

  • 这是第一个得到广泛使用的HTTP版本,其添加了版本号,各种 HTTP 首部、一些额外的方法,以及对多媒体对象的处理。
  • HTTP/1.0 使用 并行连接,通过多条 TCP 连接发起并发的 HTTP 请求,浏览器限制并行连接数通常为4个。

image.png

  • 由于多个请求是由多个 TCP 连接并行处理的,各个请求之间互不影响,所以并没有队头阻塞的问题
  • 当然如果请求数超过4个,那后面的请求是要排队等待的
  • 也会受到 TCP 队头阻塞的影响。

2 HTTP/1.1

1 持久连接

  • 实际上在HTTP/1.0中就可以实现持久连接,但并不是默认设置,HTTP/1.1开始持久连接是默认设置
  • 持久连接,即重用 TCP 连接,以消除每个连接都需要进行TCP的握手同步阶段

image.png

  • HTTP/1.1也会启用多个并行连接,对于同一个连接里的多个请求,后面的请求会受到前面的影响,也就是有队头阻塞的问题

只不过对于同一个连接里的多个请求,其只有第一个要进行三次握手,后面的请求都不需要了,所以要比 HTTP/1.0 快

  • 当然HTTP/1.1还会受到 TCP 本身队头阻塞的影响

2 管线化技术

  • 使用持久连接后,使得管线化技术成为可能
  • HTTP管线化(HTTP pipelining)是将多个HTTP请求(request)整批提交的技术,而在发送过程中不需先等待服务器的回应

image.png

  • 多个并行请求间是不会有队头阻塞问题的,但是非并行的请求间仍然有队头阻塞问题
  • TCP 队头阻塞同样会影响它。

3 HTTP/1.1顺序发送的原因

  • 无论是否使用管线化技术,HTTP/1.1中,共享同一TCP连接的HTTP报文总是先请求,在收到响应后才能再发起请求,即顺序发送,造成这一情况的原因是TCP粘包问题

  • 由于 TCP 是面向流的协议,发送端多次发送的数据传送到接收端后,数据有可能是黏在一起的,也就是常说的 TCP黏包。严格来说这不是一个问题,因为这就是它要做的事。

  • 当多个请求使用同一个连接时,他们的数据是连接在一起的,HTTP 使用 Content-Length首部 来区分数据长度,另外还有一种方法是使用 chunked 编码(分块传输编码),说白了就是在数据末尾加上一个结束的标识符来进行区分。
  • 由于TCP是不会给你区分数据是来自哪一个请求的,HTTP/1.1 的解决办法是按顺序发送,并且按顺序返回。比如先发送了 A 请求之后再发送 B 请求,那么服务端一定要先返回 A 请求的数据,即使 B 请求已经处理完了,这样就做到了请求的区分,由此也带来了队头阻塞的问题

    3 HTTP/2.0

  • HTTP/2.0使用 SPDY协议 作为起点,并使用多路复用(单个连接上可以进行并行交错的请求和响应,之间互不干扰)解决了队头阻塞的问题

image.png

  • 之所以HTTP/2.0在同一个TCP上的多个请求可以相互交错,是因为每个请求的数据都是被单独放在不同帧里的,每个帧都有一个流标识号,同一个请求可能会有多个帧,共同组成同一个流

实际发送的帧数据,通过流标识号可以区分是哪一个请求,从而解决了必须顺序发送问题,进而解决了 HTTP 队头阻塞

  • HTTP/2.0仍然无法避免TCP本身的队头阻塞问题,而且对其影响更大,因为多个同域名的请求都只会使用同一个 TCP 连接,不会有多个并行连接。

4 HTTP/3

可以看到上面不管是持久连接还是多路复用,都会受到 TCP 队头阻塞的影响,所以HTTP/3直接弃用 TCP 协议,改用基于UDP协议的QUIC协议来实现
image.png