HTTP/0.9 和早期的 HTTP/1.0 协议对 HTTP 请求处理是串行化的。假如一个页面包含 3 个样式文件,同属于一个协议、域名、端口。那么,浏览器一共须要发起四次请求,而且每次只能打开一个 TCP 通道,在一个请求资源完成下载后,马上断开该链接,再开启一个新的链接去处理队列中的下一个请求。随着页面资源大小、数量的不断扩增,网络延迟时间会不断堆积,用户会面对满屏空白,等待过长时间而失去耐心。浏览器
为了提升网络的吞吐能力,改进后的 HTTP 协议容许客户端同时打开多个 TCP 链接,并行地请求多个资源,充分利用带宽。一般,每个链接之间都会有必定延迟,但请求的传输时间是重叠的,整体上时延要比串行链接低不少。考虑到每个链接都会消耗系统资源,而且服务器须要处理海量的用户并发请求,浏览器会对并发请求数量作必定的限制。即便 RFC 并无规定具体的限制数量,各浏览器厂商也都会有本身的标准:缓存
早期的 HTTP 协议对每一个请求都占用一个独立的 TCP 链接,这无疑增长了 TCP 的创建链接开销、拥塞控制开销、释放链接开销,改进后的 HTTP/1.0 和 HTTP/1.1(默认)都支持了持久链接。若是一个请求完成后,不会马上断开链接,而是在必定的时间内保持链接,以便快速处理即将到来的 HTTP 请求,复用同一个 TCP 通道,直到客户端心跳检测失败或服务器链接超时。这个特性能够经过 HTTP 首部 Connection: keep-alive
来激活,客户端也能够发送 Connection: close
来主动关闭链接。因此,咱们看到,并行链接和持久链接这两种优化是相辅相成的,并行链接使得首次加载页面能够同时打开多个 TCP 链接,而持久链接保证了后续的请求复用已打开的 TCP 链接,这也是现代 Web 页面的广泛机制。服务器
持久链接让咱们能够重用链接来完成屡次请求,但它必须知足 FIFO 的队列顺序,必须保证前一个请求成功到达服务器、处理成功而且收到服务器返回的首个字节,才能够发起队列中下一个请求。HTTP 管道容许客户端在同一个 TCP 通道内连续发起多个请求,而没必要等待响应,消除了往返延迟时间差。但现实状况因为 HTTP/1.x 协议的限制,不容许数据在一个链路上交错到达(IO 多路复用)。设想一种状况,客户端服务器端同时发送一个 HTML 和多个 CSS 请求,服务器并行处理全部请求,当全部的 CSS 请求处理完成并加入到缓冲队列,却发现 HTML 请求处理遇到问题而无限被挂起,严重时甚至形成缓冲区溢出,这种状况就叫作队首阻塞。所以,这个方案在 HTTP/1.x 协议中并无被采纳。网络
队首阻塞并非 HTTP 中独有的概念,而是在缓存式通讯网络交换中的一种广泛现象并发