Open sufuwang opened 1 year ago
本地开启两个 Server ,逻辑如下所示
function fn(res) {
if (req.url === "/") {
res.end(readFileSync(__dirname + "/../src/index.html", "utf8"));
return;
}
res.end("ok");
}
index.html
的逻辑如下所示
const handle = async () => await fetch('a')
Promise.all([...new Array(500)].map(() => handle()))
HTTP1.1 的 Network 如下图所示
HTTP2 的 Network 如下图所示
HTTP2 的 Stalled 和 Finish 时间、Connect 数都是小于 HTTP1.1 的,但是 HTTP2 并未真正解决队头阻塞的问题,在 HTTP2 中还是需要等待上一个请求完成再去执行下一个请求,在 TCP 协议下无法真正解决队头阻塞,即 TCP 数据包的顺序响应。有很多文章中说 HTTP2 解决了队头阻塞问题,这里的队头阻塞指的是 HTTP 应用曾协议层面的问题,即 HTTP1.1 必须顺序响应,前一个请求的延迟将同步体现到后续所有请求上,而 HTTP2 则使用分帧做到了乱序响应。下面来对比一下顺序响应带来的影响
本地开启两个 Server ,逻辑如下所示
function fn(res) {
if (req.url === "/") {
res.end(readFileSync(__dirname + "/../src/index.html", "utf8"));
return;
}
if (req.url === "/delay") {
setTimeout(() => {
res.end("ok");
}, 50);
return;
}
res.end("ok");
}
index.html
的逻辑如下所示
const handle = async () => await fetch('a')
const delay = async () => await fetch('delay')
Promise.all([...new Array(500)].map((d, i) => i === 200 ? delay() : handle()))
HTTP1.1 的 Network 如下图所示
HTTP2 的 Network 如下图所示
对比可得,HTTP1.1 一个出现网络波动的请求,会对后续的所有请求造成影响,这并不是绝对的,当耗时超出阈值时,HTTP1.1 会新开一个 TCP 链接,如下图所示,图片已经按照 connect id 排序
多路复用可以 解决 “多个 TCP 链接” 问题,二进制分帧可以 减缓 “队头阻塞” 问题,解决的是 HTTP 应用层协议的 “队头阻塞”,并没有解决 TCP 传输层协议的 “队头阻塞”
Chrome 文档: Timing breakdown phases explained
名称 | 描述 |
---|---|
Queueing | 请求在队列中的等待时间。存在以下三种情况时,请求会进队列等待:有更高优先级的请求、HTTP1.x 下的 6 个TCP 链接都被占用、Chrome 正在分配磁盘缓存空间 |
Stalled | Chrome 等待请求可以被发送的时间,包括等待代理协商的时间、等待可复用的 TCP 链接被先前需求释放的时间,不包括 DNS 查询时间、TCP 链接建立的时间 |
DNS Lookup | DNS 查询耗时 |
Initial connection | 通讯建立的耗时,包括 TCP 握手/重试耗时、SSL 握手耗时 |
Proxy negotiation | 代理服务器协商耗时 |
Request sent | 请求发送耗时 |
ServiceWorker Preparation | Service Worker 启动耗时 |
Waiting (TTFB) | TTFB = Time To First Byte ,请求发送后到收到响应首字节的等待时间 |
Content Download | Chrome 接收从 Server / Worker 响应的耗时,耗时较长除了网络和 Server 的因素外,还有可能是 Chrome 无暇处理响应而导致耗时较长 |
~Receiving Push~ | ~HTTP2 Server Push 耗时~ |
~Reading Push~ | ~读取 Server Push 缓存的耗时~ |
二进制分帧是 HTTP2 对 HTTP1.1 优化的核心。这小节来学习二进制分帧为什么可以解决 HTTP 应用层协议的 “队头阻塞” 问题
HTTP2 中存在一个 TCP 链接,在这个链接中存在许多双向数据流,HTTP1.1 的一个消息被分成多个帧,通过这些双向数据流进行并发传输,在接收端进行重组,这些发生在二进制分帧层,处于应用层和传输层之间。TCP 协议的滑动窗口是一个队列,不能并发处理消息,所以这些并不能真正解决 “队头阻塞”
HTTP2 使用 HPACK 算法完成 Header 压缩,大概原理如下
HTTP1.1 的 Header
HTTP2 的 Header
背景
HTTP1.1 存在以下问题
针对以上问题,HTTP2 协议 RFC-7540 诞生并发布于 2015 年,做了以下事情来解决这些问题
Chrome 较早是支持 Server Push 的,但出于一些原因,Chrome 不再支持 Server Push,所以现在学习一下前三种方法
eg: HTTP1.1 & HTTP2 性能对比