HTTP/1.0 ![](../assets/HTTP 性能 - 20240702202645224.jpg) HTTP/1.0 是无状态、无连接的应用层协议。 队头阻塞 (head of line blocking),由于 HTTP1.0 规定下一个请求必须在前一个请求响应到达之前才能发送,后面的一直在等重传。 ![](../assets/HTTP 性能 - 20240702202742862.jpg)
缓存 ![](../assets/HTTP 性能 - 20240702203023533.jpg)
HTTP1.0 不支持断点续传功能,每次都会传送全部的页面和数据。如果只需要部分数据就会浪费多余带宽
1.0 每一次通信都要重新建立 TCP 连接 - 通 - 信断开连接过程,为了解决这个问题 1.1 引入长连接:一个 TCP 连接上可以传输多个请求,减少 TCP 建立连接和断开连接的次数
同时浏览器为每个域名最多同时维护 6 个 TCP 持久连接,使用 CDN 的实现域名分片,加快速度
但当前一个请求没有响应时,会阻塞后面的所有请求(队头阻塞),试图通过管线化解决,可以并行多个请求,但是返回值还是需要按照请求顺序(只是解决了请求的队头阻塞问题)(原因是因为协议中没有可以表示请求的 id,只能通过请求顺序来识别响应)
而且带宽利用率不高,原因:
- TCP 的慢启动(减少网络拥塞策略)** 推迟了宝贵的首次渲染页面
- 同时开启了多条 TCP 连接,那么这些连接会竞争固定的带宽(不能协调资源优先级,关键资源应该先返回)
- HTTP/1.1 队头阻塞的问题
HTTP 1.1
- 无状态
好处:服务器不用额外资源记录,减轻服务器负担,提高 CPU 内存利用效率
坏处:每次都要确认验证信息;一般通过 Cookie 解决(Cookie 通过在请求和响应报文中写入 Cookie 信息来控制客户端的状态。) - 明文传输: 传输过程中信息可以抓包直接获取,信息暴露、安全性差
为了解决早期 HTTP/1.0 每次都要建立连接导致通信效率低的性能问题,因为 HTTP 基于 TCP/IP 协议 为了解决上述 TCP 连接问题,HTTP/1.1 提出了长连接的通信方式,也叫持久连接。这种方式的好处在于减少了 TCP 连接的重复建立和断开所造成的额外开销,减轻了服务器端的负载。
持久连接的特点是,只要任意一端没有明确提出断开连接,则保持 TCP 连接状态。如果某个 HTTP 长连接超过一定时间没有任何数据交互,服务端就会主动断开这个连接。
![](../assets/HTTP 性能 - 20240702203148204.jpg)
管道传输 因为 HTTP/1.1 采用了长连接的方式,这使得管道(pipeline)网络传输成为了可能。
即可在同一个 TCP 连接里面,客户端可以发起多个请求,只要第一个请求发出去了,不必等其回来,就可以发第二个请求出去,可以减少整体的响应时间。 但是服务器必须按照接收请求的顺序发送对这些管道化请求的响应。
HTTP 2.0 HTTP/2.0 协议是基于 HTTPS 的,更加安全 头部压缩 HTTP2.0 会压缩(Header)部分;如果同时多个请求其头部一样或相似,那么协议会消除重复部分。
二进制格式
HTTP/1.0 和 HTTP/1.1 中,报文都是纯文本的格式简单易读;而在 2.0 中采用了二进制的格式
报头和数据体称为:帧(frame)-》头信息帧(Headers Frame)和数据帧(Data Frame)
![](../assets/HTTP 性能 - 20240702202705601.jpg)
多路复用:HTTP2.0 实现了真正的并行传输,它能够在一个 TCP 上进行任意数量的 HTTP 请求,由于其二进制分帧特性
数据以数据流(stream)的形式以字节单位发送,数据包可以不按顺序发送
在 HTTP/2 中每个请求或响应的所有数据包,称为一个数据流(Stream)。每个数据流都标记着一个独一无二的编号(Stream ID); 所有 HTTP2.0 通信都在一个 TCP 链接上完成,这个链接可以承载任意流量的双向数据流。每个数据流以消息的形式发送,而消息由一或多个帧组成。不同 Stream 的帧是可以乱序发送的(因此可以并发不同的 Stream ),因为每个帧的头部会携带 Stream ID 信息,所以接收端可以通过 Stream ID 有序组装成 HTTP 消息
客户端请求的 Stream 是奇数,服务器建立的 Stream 必须是偶数号,同一 Stream 内部的帧必须是严格有序的
2.0 主要是在 http 应用层层面去解决问题
多路复用(加入二进制分帧层处理之后,会被转换为一个个带有请求 ID 编号唯一标识的帧(头部或者数据,最新单位)),故服务器可以设置优先级优先返回一些资源,因为浏览器可以通过筛选 id 拼接出结果
服务器推送:可以提前将 HTML 中的 css,js 关键资源一起返回,而不需要浏览器拿到 HTML 解析后再去请求
头部压缩,对请求头和响应头进行了压缩,两边维护字典,只传送索引,减小体积,也算了将变(请求体)和不变(请求头)分离的一直思想
HPACK 算法:(核心是通过编码方式生成体积更小的索引)
客户端和服务器两端都会建立和维护字典,哈夫曼压缩
服务端推送:HTTP/2 还在一定程度上改善了传统的「请求 - 应答」工作模式,服务端不再是被动地响应,可以主动向客户端发送消息、推送额外的资源。客户端在访问 html 时服务端直接推送 css 减少时间
tcp 依旧会队头阻塞
![](../assets/HTTP 性能 - 20240702202757163.jpg)
HTTP 3.0
基于 Google 的 QUIC,HTTP3 背后的主要思想是放弃 TCP,转而使用基于 UDP 的 QUIC 协议。
为了解决 HTTP/2.0 中 TCP 造成的队头阻塞问题,HTTP/3.0 直接放弃使用 TCP,将传输层协议改成 UDP;但是因为 UDP 是不可靠传输,所以这就需要 QUIC 实现可靠机制
QUIC 特点:多个 Stream 之间并没有依赖,都是独立的 无队头阻塞;1RTT 握手快;
三层头部:![](../assets/HTTP 性能 - 20240702203720887.jpg)
QUIC 报文中的 Pakcet Number 是严格递增的, 即使是重传报文,它的 Pakcet Number 也是递增的,这样就能更加精确计算出报文的 RTT。 QUIC 使用的 Packet Number 单调递增的设计,可以让数据包不再像 TCP 那样必须有序确认,QUIC 支持乱序确认,当数据包 Packet N 丢失后,只要有新的已接收数据包确认,当前窗口就会继续向右滑动。
QUIC 是如何迁移连接的? 基于 TCP 传输协议的 HTTP 协议,由于是通过四元组(源 IP、源端口、目的 IP、目的端口)确定一条 TCP 连接。那么当移动设备的网络从 4G 切换到 WIFI 时,意味着 IP 地址变化了,那么就必须要断开连接,然后重新建立 TCP 连接。
QUIC 协议没有用四元组的方式来 “绑定” 连接,而是通过连接 ID 来标记通信的两个端点,客户端和服务器可以各自选择一组 ID 来标记自己,因此即使移动设备的网络变化后,导致 IP 地址变化了,只要仍保有上下文信息(比如连接 ID、TLS 密钥等),就可以 “无缝” 地复用原连接,消除重连的成本,没有丝毫卡顿感,达到了连接迁移的功能。
![](../assets/HTTP 性能 - 20240702202808029.jpg)
3.0 主要是在解决传输层 QUIC 去解决问题
2.0 没有解决 tcp (可靠)层面的队头阻塞问题(字节流协议必须保证收到的数据是连续完整的,丢包触发重传),以及连接握手 1.5RTT
- 基于 udp, 引入 quic 类似 TCP 的流量控制、传输可靠性的功能
- 集成 TLS,减少 RTT,只需要 1RTT(握手的目的是为确认双方的「连接 ID」)
- 实现类似 HTTP2 的多路复用想
- 连接迁移,IP、改变也可以无缝复原连接(ID 表示,不是四元组)