HTTP/1的缺陷
- 队头阻塞
- 1.1版本实现了管道化,允许一次发送一组请求
- 但是响应的返回必须按照顺序
- 如果第一个请求时间很长,后面的请求的响应都会被堵塞
- HTTP/2的Multiplexing功能则可以真正意义上实现数据的同时发送与同时接收,不用再被队头阻塞限制
- 不过HTTP/2也只是解决了应用层协议的队头阻塞问题,而传输层的队头阻塞问题没有被解决
- TCP的队头阻塞
- 由于TCP的工作原理,当数据包按顺序到达后才能push到上层去处理,如果这中间有一个数据没有到达,但其后面的数据已经到了。那么,只有当前面的数据到达后,才能把后面早就到达的数据发送到上层去
- TCP慢启动导致原本就具有突发性和短时性的 HTTP 连接变的十分低效
- 消息首部无法压缩
- 例如有cookie,首部会很大
- 体积巨大的 HTTP 头部会占据请求的很大部分
HTTP/2 格式
- URL中老的 scheme 不会变,没有
http2://
HTTP/2 传输过程
- HTTP2中TLS可选项,规范并不强制性应用
- 但是主流浏览器 HTTP/2 的实现都是基于 SSL/TLS 的,也就是说使用 HTTP/2 的网站都是 HTTPS 协议
- 基于h2的grpc可以选择跳过该步骤,此时协议简写为
h2c
,而不是h2
- HTTP/2 连接创建方式
- 协商升级协议方式
- 假如不知道服务端是否支持 HTTP/2,可以先使用 HTTP/1.1 进行协商
- 服务端接收到协商请求之后,如果不支持 HTTP/2,则直接按照 HTTP/1.1 响应返回
- 如果服务端支持 HTTP/2, 则协商成功,返回 101 结果码,通知客户端一起升级到 HTTP/2 进行通信
- 101 响应之后,服务需要发送 SETTINGS 帧作为连接序言,客户端接收到 101 响应之后,也必须发送一个序言作为回应
- 客户端序言发送完成之后,可以不需要等待服务端的 SETTINGS 帧,而直接发送业务请求 Frame
- 假如不知道服务端是否支持 HTTP/2,可以先使用 HTTP/1.1 进行协商
- 直接连接方式
- 假如客户端和服务端已经约定使用 HTTP/2, 则可以免去 101 协商和切换流程
- 协商升级协议方式
HTTP/2的优化
首部压缩
- 通过静态霍夫曼码对发送的header字段进行编码,减小了它们的传输大小
- 客户端和服务器使用索引表来维护和更新header字段
- 对于相同的数据,不再重复发送
二进制协议
- HTTP/1的解析是基于文本分割的
- 每一行的结尾会有分隔符(\r\n)
- 一次只能处理一个请求,完成前不能中断
- 无法预估一次解析需要预留多少内存(一行多长)
- 引入新的二进制分帧数据层传输数据
- 采用二进制格式的编码
- HTTP/2的请求和响应由一个HEADERS帧和许多DATA帧构成
- 帧的大小固定
- 这些帧可以交错发送,然后根据每个帧首部的流标识符重新组装
多路复用
- 客户端向某个域名的服务器请求页面的过程中,只会创建一条TCP连接,即使这页面可能包含上百个资源
- 虽然只有一条TCP连接,但是在逻辑上分成了很多stream
- TCP连接的复用避免了多次慢启动
- 流(Stream)
- 已建立的连接上的双向字节流
- 每个流都有一个唯一的整数标识符streamID
- 接收端的实现可据此并发组装消息
- 客户端或者服务器都可以创建或关闭一条Stream
- 新建立的流 ID 必须大于曾经建立过的状态为 opened 或者 reserved 的流 ID
- Stream ID 不能复用,长连接耗尽 ID 应创建新连接
- 同一 Stream 内的 frame 必须是有序的
- 每个数据流有优先级
- 确保在有限的带宽中优先加载最重要的资源
- 例如首页的html就应该优先展示,然后才是一些静态资源文件、脚本文件等,这样就可以确保用户可以第一时间看到页面内容了
服务端推送
- 基于已发送的请求提前将资源推送至浏览器缓存
- 例如客户端请求 html,主动推送 js 文件
- 推送资源必须对应一个请求
- 从 Stream ID 的值可以分辨 PUSH 消息
- 所有客户端发送的流,从奇数开始递增
- 所有服务端推送的流,从偶数开始递增
流量控制
- 多路复用意味着多个 Stream 必须共享 TCP 层的流量控制
- 多 Stream 争夺 TCP 的流控制,互相干扰可能造成 Stream 阻塞
- 流量控制有方向性,即接收方可能根据自己的情况为每个流,乃至整个连接设置任意窗口大小
- 连接建立后,客户端与服务器交换SETTINGS帧,设置 双向的流量控制窗口大小
- 流量控制窗口大小通过WINDOW_UPDATE帧更新
- HTTP/2流量控制和TCP流量控制的机制相同,但TCP流量控制不能对同一个连接内的多个流实施差异化策略
HTTP/3(QUIC )协议展望
- 基于UDP而不是TCP
- 不在OS的内核中进行开发
- 优点
- UDP之上的多路复用(不再有TCP队头阻塞的困扰)
- 其中即使属于某个stream的某个frame丢失了,也仅仅只是影响这个stream,而不会影响到其他的stream
- 与TLS不同,QUIC仅需要使用1个RTT就可以完成秘钥交换
- 采用DH秘钥交换算法
- Package Pacing
- 通过追踪包到达的时间来预测当前网络带宽的使用情况,以决定是否提高、保持或降低发送包的速率来避免网络拥塞和丢包的情况发生
- 连接迁移
- 一条TCP连接是由四元组确立的,在网络(环境)发生变化的时候,则需要重新建立连接
- 例如4G与wifi的切换或从一个地方移动到另一个地方
- 一条QUIC连接是由一个64位随机数作为ID进行标识的
- 也无论IP或者端口发生变化,只要ID不变,则该连接依然有效,无需进行重连,而上层业务不会感知变化
- 一条TCP连接是由四元组确立的,在网络(环境)发生变化的时候,则需要重新建立连接
- UDP之上的多路复用(不再有TCP队头阻塞的困扰)