web性能优化技巧篇之多路复用

258 阅读2分钟

这是我参与11月更文挑战的第14天,活动详情查看:2021最后一次更文挑战

多路复用

上篇中讲到的连接复用是 HTTP/1.1 时期的常用优化手段,而到了 HTTP/2.0,又有了新的优化手段:多路复用。

我们先来看看「连接复用」的缺点:虽然让多次请求响应只占用一个 TCP 连接,但是请求响应依然是「串行」的,就如同烧烤签的上肉块,一个接一个。有没有可能做到:

  1. 多个请求同时出现在一个 TCP 连接里
  2. 多个响应同时出现在一个 TCP 连接里
  3. 请求和响应同时出现在一个 TCP 连接里

这就如同把一个很窄的单向通行车道,扩展成很宽的双向通行车道。HTTP/2.0 可以做到这一点。 这一切都得益于 HTTP/2.0 对比于 HTTP/1.1 做出的如下重要变动:

  1. 引入了帧(Frame)的概念,每一帧包含 Length + Type + Flags + StreamID + Payload 五部分,前四个部分是固定的长度,为 9 字节,第五部分 Payload 的最大长度为 214 2^{14}22412^{24}-1 字节,即 16Kb 到 16Mb,具体的最大长度由终端自行决定。
  2. 保留了请求和响应的概念,请求头和响应头会被发送方压缩后,分成几个连续的 Frame 传输,头字段会出现在这些 Frame 的 Payload 中;接收方拼合这些 Frame 后,解压缩即可得到真正的请求头或响应头。
  3. 引入了流(Stream)的概念,一个 Stream 由双向传输的连续且有序的 Frame 组成,一个 TCP 连接可以同时包含多个 Stream(比如 100 个),一个 Stream 只用于一次请求和一次响应。Stream 之间不会互相影响。
  4. 服务端可以先发响应,客户端拿到响应结果后可以保存,之后就不需要再发对应的请求了。
  5. 头部字段全部改为小写,不允许出现大写。比如:accept: text/html
  6. 引入了伪头部字段的概念,出现在头部字段的前面,必须以冒号开头。比如:method: GET

HTTP/1.1 和 HTTP/2.0 比较

无消息体的 GET 请求

HTTP/1.1

GET /resource HTTP/1.1
Host: example.org
Accept: image/jpeg

HTTP/2.0

HEADERS
    + END_STREAM
    + END_HEADERS
    :method = GET
    :scheme = https
    :path = /resource
    host = example.org
    accept = image/jpeg

有消息体的 POST 请求

HTTP/1.1

POST /resource HTTP/1.1
Host: example.org
Content-Type: image/jpeg
Content-Length: 123
{消息体}

HTTP/2.0

HEADERS
    - END_STREAM
    - END_HEADERS
    :method = POST
    :path = /resource
    :scheme = https
CONTINUATION
    + END_HEADERS
    content-type = image/jpeg
    host = example.org
    content-length = 123
DATA
    + END_STREAM
{消息体}

响应

HTTP/1.1

HTTP/1.1 200 OK
Content-Type: image/jpeg
Content-Length: 123
{binary data}

HTTP/2.0

HEADERS
    - END_STREAM
    + END_HEADERS
    :status = 200
    content-type = image/jpeg
    content-length = 123
DATA
    + END_STREAM
{消息体}

最后说一句

如果这篇文章对您有所帮助,或者有所启发的话,帮忙关注一下,您的支持是我坚持写作最大的动力,多谢支持。