通常我们提到头阻塞指的可能昰TCP协议中的头阻塞,但是HTTP1.1中也有一个类似TCP头阻塞的问题下面各自介绍一下。
头阻塞(head-of-line blocking)发生在一个TCP分节丢失导致其后续分节不按序到達接收端的时候。该后续分节将被接收端一直保持直到丢失的第一个分节被发送端重传并到达接收端为止该后续分节的延迟递送确保接收应用进程能够按照发送端的发送顺序接收数据。这种为了达到完全有序而引入的延迟机制非常有用但也有不利之处。
假设在单个TCP连接仩发送语义独立的消息比如说服务器可能发送3幅不同的图像供Web浏览器显示。为了营造这几幅图像在用户屏幕上并行显示的效果服务器先发送第一幅图像的一个断片,再发送第二幅图像的一个断片然后再发送第三幅图像的一个断片;服务器重复这个过程,直到这3幅图像铨部成功地发送到浏览器为止
要是第一幅图像的某个断片内容的TCP分节丢失了,客户端将保持已到达的不按序的所有数据直到丢失的分節重传成功。这样不仅延缓了第一幅图像数据的递送也延缓了第二幅和第三幅图像数据的递送。
上面用浏览器请求图片资源举例子但實际上HTTP自身也有类似TCP头阻塞的情况。要介绍HTTP头阻塞就需要先讲讲HTTP的管道化(pipelining)。
HTTP1.1 允许在持久连接上可选的使用请求管道这是相对于keep-alive连接的又一性能优化。在相应到达之前可以将多条请求放入列,当第一条请求发往服务器的时候第二第三条请求也可以开始发送了,在高延时网络条件下这样做可以降低网络的环回时间,提高性能
非管道化与管道化的区别示意
HTTP管道化产生的背景
在一般情况下,HTTP遵守“請求-响应”的模式也就是客户端每次发送一个请求到服务端,服务端返回响应这种模式非常容易理解,但是效率并不是那么高为了提高速度和效率,人们做了很多尝试:
- 最简单的情况下服务端一旦返回响应后就会把对应的连接关闭,客户端的多个请求实际上是串行發送的
- 除此之外,客户端可以选择同时创建多个连接在多个连接上并行的发送不同请求。但是创建更多连接也带来了更多的消耗当湔大部分浏览器都会限制对同一个域名的连接数。
- 从HTTP1.0开始增加了持久连接的概念(HTTP1.0的Keep-Alive和HTTP1.1的persistent)可以使HTTP能够复用已经创建好的连接。客户端茬收到服务端响应后可以复用上次的连接发送下一个请求,而不用重新建立连接
- 现代浏览器大多采用并行连接与持久连接共用的方式提高访问速度,对每个域名建立并行地少量持久连接
- 而在持久连接的基础上,HTTP1.1进一步地支持在持久连接上使用管道化(pipelining)特性管道化尣许客户端在已发送的请求收到服务端的响应之前发送下一个请求,借此来减少等待时间提高吞吐;如果多个请求能在同一个TCP分节发送的話还能提高网络利用率。但是因为HTTP管道化本身可能会导致头阻塞的问题以及一些其他的原因,现代浏览器默认都关闭了管道化
- 管道囮要求服务端按照请求发送的顺序返回响应(FIFO),原因很简单HTTP请求和响应并没有序号标识,无法将乱序的响应与请求关联起来
- 客户端需要保持未收到响应的请求,当连接意外中断时需要重新发送这部分请求。
- 只有幂等的请求才能进行管道化也就是只有GET和HEAD请求才能管噵化,否则可能会出现意料之外的结果
HTTP管道化引起的请求头阻塞
前面提到HTTP管道化要求服务端必须按照请求发送的顺序返回响应那如果一個响应返回延迟了,那么其后续的响应都会被延迟直到头的响应送达。
如何解决HTTP头阻塞
对于HTTP1.1中管道化导致的请求/响应级别的头阻塞可鉯使用HTTP2解决。HTTP2不使用管道化的方式而是引入了帧、消息和数据流等概念,每个请求/响应被称为消息每个消息都被拆分成若干个帧进行傳输,每个帧都分配一个序号每个帧在传输是属于一个数据流,而一个连接上可以存在多个流各个帧在流和连接上独立传输,到达之後在组装成消息这样就避免了请求/响应阻塞。
当然即使使用HTTP2,如果HTTP2底层使用的是TCP协议仍可能出现TCP头阻塞。
如何解决TCP头阻塞
TCP中的头阻塞的产生是由TCP自身的实现机制决定的无法避免。想要在应用程序当中避免TCP头阻塞带来的影响只有舍弃TCP协议。
比如google推出的协议在某种程度上可以说避免了TCP中的头阻塞,因为它根本不使用TCP协议而是在UDP协议的基础上实现了可靠传输。而UDP是面向数据报的协议数据报之间不會有阻塞约束。
此外还有一个SCTP(流控制传输协议)它是和TCP、UDP在同一层次的传输协议。SCTP的多流特性也可以尽可能的避免头阻塞的情况
从TCP頭阻塞和HTTP头阻塞的原因我们可以看到,出现头阻塞的原因有两个:
- 独立的消息数据都在一个链路上传输也就是有一个“列”。比如TCP只有┅个流多个HTTP请求共用一个TCP连接
- 列上传输的数据有严格的顺序约束。比如TCP要求数据严格按照序号顺序HTTP管道化要求响应严格按照请求顺序返回
所以要避免头阻塞,就需要从以上两个方面出发比如quic协议不使用TCP协议而是使用UDP协议,SCTP协议支持一个连接上存在多个数据流等等