多路复用
问题发现
默认情况下,浏览器会限制同一域名下的最大连接数(通常是 6 个,浏览器也可能会在未来改动,并且不能自行设置),对于需要处理大量请求或包含较大资源的站点而言,会出现以下现象,影响网页的加载速度:
- 受限于浏览器的最大连接数,当请求数达到并发限制后,后续请求需要等待前面请求完成,且释放连接后方可继续(HTTP/1.1 队头阻塞)
- 每一个请求对应一个连接,请求开始时创建,响应结束后关闭,导致 TCP 连接<可能>会频繁的创建与关闭(DNS 查询、三次握手与四次挥手会产生往返时延)。
HTTP 1.1 协议规定(RFC2616):单用户客户端不应该与任何服务器或代理机构保持超过 2 个连接。(理由则是为了减少服务器的负担与安全考虑。)
但是现代浏览器的限制比较宽松(2 个怎么够?),允许了更大的连接数。RFC 也并没有说明如何防止超过限制的问题,浏览器连接数限制参考对照表:connection_limitations。
相关问题:max-parallel-http-connections-in-a-browser,包含了如何查看浏览器限制数量、历版本的数量变化等相关话题的讨论。
例如,当受网络因素影响时,通过 Chrome Lighthouse 评估之后,可能会给出启用 HTTP/2 来加速获取资源的建议。
解决方法
通过配置服务器(或向运维工程师申请协助)启用 HTTP/2 并利用其多路复用的特性,是解决该问题最简单的方法。
# Nginx 配置示例
server {
listen 443 http2;
}
名词释义
队头阻塞(HOL Blocking):HTTP/1.1 采用的是请求-响应模型(即 P2P),后续的请求必须等待前面的请求完成之后才可进行。因此浏览器提供了并发请求的能力,但也限制了最大并发数。
帧(Frame)和流(Stream):HTTP/2 支持二进制数据帧传输,取代了 HTTP/1.1 的文本传输格式,解析更为高效。而帧是 HTTP/2 传输的最小数据单位,且会标识为属于哪一个流。
多路复用(Multiplexing):多个数据流(虚拟信道/逻辑信道)复用同一个连接(物理信道)。
此处特指 HTTP/1.1 的队头阻塞问题,因为 TCP 也存在队头阻塞的问题
未启用 HTTP/2
通过在控制台观察可知,在未启用 HTTP/2 的情况下,由于前面的资源正在加载中,且达到了浏览器限制的最大并发数,后续的资源加载则必须排队等待。
已启用 HTTP/2
得益于 HTTP/2 帧分片、多路复用等特性,一个 TCP 连接可以交替乱序传输多个资源请求对应的数据流,因此无 HTTP/1.1 队头阻塞的问题。
文本压缩
服务器配置
# Nginx 配置示例
server {
gzip on;
}