编程开源技术交流,分享技术与知识

网站首页 > 开源技术 正文

什么是队头阻塞?(队列队头队尾是哪里)

wxchong 2024-09-11 10:38:03 开源技术 9 ℃ 0 评论

之前面试就被问到过这个问题,在面试前我也刷到过类似的题目,当时想着这么复杂的问题应该不会问,所以就只是粗略地看了一下。到了面试的时候,被面试官各种深挖,把我自己都搞晕了!

面试完后,面试官说虽然问的问题都懂,但是没有把它们联系起来。

事后,我在网上搜索了大量资料,又翻看了好几本网络相关的书籍,这才完全理清。

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

下面我就来分别说说这两种情况,两种协议间的关系我也会穿插在其中,希望能在这个过程中把网络原理中的各个知识点联系起来,达到融会贯通的效果。

TCP 队头阻塞

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

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

IP 层的作用是“实现终端节点之间的通信”,并不保证数据的可靠性和有序性,所以接收端可能会先收到窗口末端的数据,这个时候 TCP 是不会向上层应用交付数据的,它得等到前面的数据都接收到了才向上交付,所以这就出现了队头阻塞,即队头的包如果发生延迟或者丢失,队尾必须等待发送端重新发送并接收到数据后才会一起向上交付。

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

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

HTTP 队头阻塞

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

HTTP/0.9

这是个很老的协议了,我就没见过,它只支持 GET 方法,不支持多媒体内容的 MIME 类型、各种 HTTP 首部,或者版本号。

它使用 串行连接,多个请求是排队一个一个来的,只有前面的连接和数据请求处理完了,才会处理下一个,因此队头阻塞问题明显,再加上 TCP 本身的队头阻塞,简直是雪上加霜,所以它很快就被 HTTP/1.0 取代了。

HTTP/1.0

这是第一个得到广泛使用的HTTP版本,其添加了版本号,各种 HTTP 首部、一些额外的方法,以及对多媒体对象的处理。

它使用 并行连接,通过多条 TCP 连接发起并发的 HTTP 请求,浏览器限制并行连接数通常为4个。

由于多个请求是由多个 TCP 连接并行处理的,各个请求之间互不影响(网络带宽问题略),所以并没有队头阻塞的问题,当然如果请求数超过4个,那后面的请求是要排队等待的,而且也会受到 TCP 队头阻塞的影响,不过影响没有 HTTP/0.9 那么大,毕竟有4个连接。

HTTP/1.0+

这是一个非官方的事实标准,其添加了很多特性:持久的 keep-alive 连接、虚拟主机支持,以及代理连接支持。

它使用 持久连接,即重用 TCP 连接,以消除连接(三次握手)及关闭时延(四次挥手)。其也会启用多个并行连接,对于同一个连接里的多个请求,后面的请求会受到前面的影响,也就是有队头阻塞的问题,当然还会受到 TCP 本身队头阻塞的影响,只不过对于同一个连接里的多个请求,其只有第一个要进行三次握手,后面的请求都不需要了,所以要比 HTTP/1.0 快。

HTTP/1.1

这是当前主要使用的版本,其使用 管道化连接,通过共享的 TCP 连接发起并发的 HTTP 请求,会有队头阻塞的问题。当然多个并行请求间是不会有这个问题的,TCP 队头阻塞同样会影响它。

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

HTTP/2(HTTP-NG,又名 HTTP/2.0)

其使用 SPDY协议 作为 HTTP/2 的起点,并使用多路复用(单个连接上可以进行并行交错的请求和响应,之间互不干扰),解决了队头阻塞的问题,不过 TCP 本身的队头阻塞是无法避免的,而且对其影响更大,因为多个同域名的请求都只会使用同一个 TCP 连接,不会有多个并行连接。

之所以在同一个 TCP 上的多个请求可以相互交错,是因为每个请求的数据都是被单独放在不同帧里的,每个帧都有一个流标识号,同一个请求可能会有多个帧,共同组成同一个流。实际发送的帧数据,通过流标识号可以区分是哪一个请求,从而解决了 HTTP 队头阻塞。

HTTP/3

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

我个人理解其就相当于把 HTTP/1.0+ 的多个 TCP 并行连接合并为一个连接,与合并前相比,其减少了握手的数量,只要一次就行。

参考文献

《HTTP权威指南》

《HTTP/2基础教程》

《图解HTTP》

《图解TCP/IP》

《TCP/IP详解卷1:协议》

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表