网站首页 > 开源技术 正文
之前面试就被问到过这个问题,在面试前我也刷到过类似的题目,当时想着这么复杂的问题应该不会问,所以就只是粗略地看了一下。到了面试的时候,被面试官各种深挖,把我自己都搞晕了!
面试完后,面试官说虽然问的问题都懂,但是没有把它们联系起来。
事后,我在网上搜索了大量资料,又翻看了好几本网络相关的书籍,这才完全理清。
队头阻塞其实有两种,一种是 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:协议》
猜你喜欢
- 2024-09-11 一文读懂 HTTP/1、HTTP/2、HTTP/3
- 2024-09-11 云端的SRE发展与实践(云端怎么理解)
- 2024-09-11 用 Go 重构 C 语言系统,这个抗住春晚红包的百度转发引擎承接了万亿流量
- 2024-09-11 HTTP 3的前世今生及尝鲜(http3为什么比http2靠谱)
- 2024-09-11 HTTP/2是个啥东西?(柴油移动泵车是个啥东西)
- 2024-09-11 提升网站性能开发的10个技巧(如何提高网站的优化速度)
- 2024-09-11 千亿级流量来袭,如何用硬件加速技术为CPU减负?
- 2024-09-11 谷歌搜索即将启用HTTP/2 方式抓取网页内容
- 2024-09-11 HTTP跳槽涨薪篇,通俗易懂~(跳槽一次涨薪多少合适)
- 2024-09-11 Mozilla Firefox 浏览器(firefox网页)
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- jdk (81)
- putty (66)
- rufus (78)
- 内网穿透 (89)
- okhttp (70)
- powertoys (74)
- windowsterminal (81)
- netcat (65)
- ghostscript (65)
- veracrypt (65)
- asp.netcore (70)
- wrk (67)
- aspose.words (80)
- itk (80)
- ajaxfileupload.js (66)
- sqlhelper (67)
- express.js (67)
- phpmailer (67)
- xjar (70)
- redisclient (78)
- wakeonlan (66)
- tinygo (85)
- startbbs (72)
- webftp (82)
- vsvim (79)
本文暂时没有评论,来添加一个吧(●'◡'●)