问题
- 为什么浏览器会为一个域名建立6个连接?客户端和服务器的连接越多越好吗?
- 为什么会有雪碧图(Spriting)、资源内联(inlining)、域名分片(Sharding)这些网页优化手段?
HTTP/1 的队头阻塞
前置知识
- HTTP 协议和请求-应答模型;
- TCP/IP 四层模型。
HTTP/1.1请求简析
- 浏览器基于 HTTP/1.1 请求简单的script.js文件
- 浏览器基于 HTTP/1.1 请求script.js文件和style.css文件
- 浏览器基于 HTTP/1.1 “并发” 请求script.js文件和style.css文件
HTTP/1.1的问题
- 队头阻塞:
- 请求的队头阻塞(可以由 “管道” 解决)
- 响应的队头阻塞(导致 Web 性能问题的主要原因)
- “大头娃娃”,即使只发一个字节的消息,也需要 “带上一个完整的头”;
- “请求-应答” 模型的天然限制。
HTTP/2
HTTP/2 的优点
- HTTP/2 完全兼容 HTTP/1;
- 废除了起始行,统一使用头字段,在两端维护字段“Key-Value”的索引表,使用 “HPACK” 算法压缩头部信息,消除冗余数据、节约带宽;
- 全面采用二进制格式,提高解析效率,把报文切分为多种类型的二进制帧,报头里最重要的字段是流标识符,标记帧属于哪个流;
- 使用虚拟的“流”传输消息,同时实现了“多路复用”,在一个 HTTP/2 连接上可以并发多个流,也就是多个“请求 - 响应”报文,提高连接的利用率,从而解决了 HTTP/1 的“队头阻塞”问题;
- 流之间可以用 Weight 权重调节优先级,还可以直接设置流间的依赖关系;
- 支持消息推送;
- 更安全;
- 如果已经升级到了 HTTPS,那么再升级到 HTTP/2 会很简单;
- TLS 协议提供“ALPN”扩展,让客户端和服务器协商使用的应用层协议,“发现”HTTP/2 服务;
- 雪碧图(Spriting)、资源内联(inlining)、域名分片(Sharding)这些手段会对 HTTP/2 的性能优化造成反效果。
HTTP/2 的问题
- 虽然协议支持 “明文” 版本,但主流浏览器只支持 “加密” 版;
- TCP协议仍然存在 “队头阻塞”,所以 HTTP/2 在弱网下的性能表现可能不如 HTTP/1。
HTTP/2 请求简析
HTTP/2多路复用响应script.js和style.css
“流” 传输解决队头阻塞问题
TCP 队头阻塞导致 HTTP 队头阻塞
- 在上面的请求里,数据包2丢失会队头阻塞数据包3
- TCP层队头阻塞会最终导致HTTP阻塞
HTTP/3
HTTP/1.1 vs HTTP/2 vs HTTP/3 响应script.js
TCP 和 QUIC 的差异
HTTP/3 解决的问题
- HTTP/3 的目标是优化传输层协议,保留了 HTTP/2 协议在应用层上的优秀设计;
- 使用 QUIC 协议解决了 TCP 层的队头阻塞。
HTTP/3 的问题
- QUIC 在单个资源流中保留排序,所以仍然存在 “队头阻塞”
Tips
为什么不是 HTTP/2.0 ?
HTTP/2 工作组认为以前的“1.0”“1.1”造成了很多的混乱和误解,让人在实际的使用中难以区分差异,所以就决定 HTTP 协议不再使用小版本号(minor version),只使用大版本号(major version),从今往后 HTTP 协议不会出现 HTTP/2.0、2.1,只会有“HTTP/2”“HTTP/3”……
HTTP/2 的高性能实现原理
静态表和 Huffman 编码可以将 HTTP 头部压缩近一半的体积,但这只是连接上第 1 个请求的压缩比。后续请求头部通过动态表可以压缩 90% 以上,这大大提升了编码效率。当然,动态表也会导致内存占用过大,影响服务器的总体并发能力,因此服务器会限制 HTTP/2 连接的使用时长。
HTTP/2 的另一个优势是实现了 Stream 并发,这节约了 TCP 和 TLS 协议的握手时间,并减少了 TCP 的慢启动阶段对流量的影响。同时,Stream 之间可以用 Weight 权重调节优先级,还可以直接设置 Stream 间的依赖关系,这样接收端就可以获得更优秀的体验。
HTTP/2 支持消息推送,从 HTTP/1.1 的拉模式到推模式,信息传输效率有了巨大的提升。HTTP/2 推消息时,会使用 PUSH_PROMISE 帧传输头部,并用双号的 Stream 来传递包体,了解这一点对定位复杂的网络问题很有帮助。
HTTP/2 的最大问题来自于它下层的 TCP 协议。由于 TCP 是字符流协议,在前 1 字符未到达时,后接收到的字符只能存放在内核的缓冲区里,即使它们是并发的 Stream,应用层的 HTTP/2 协议也无法收到失序的报文,这就叫做队头阻塞问题。解决方案是放弃 TCP 协议,转而使用 UDP 协议作为传输层协议,这就是 HTTP/3 协议的由来。
参考资料
- (译)Robin Marx: QUIC 和 HTTP/3 队头阻塞的细节
- 极客时间《透视HTTP协议》专栏
- 详解 HTTP/2 头压缩算法 —— HPACK
- 本文作者: Peter Luo
- 本文链接: http://luopeike.com/关于HTTP的队头阻塞问题/
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!