HTTP/2优势在哪
学习资源 小林coding 2022.4.4
HTTP/1.1性能问题
- 消息大小变大
- 资源变多
- 内容形式多样
- 实时性要求高
HTTP/1.1高延迟 -> 影响用户体验
- 延迟难以下降
- 并发数量有限 每个连接TCP TLS握手 TCP慢启动
- 队头阻塞 同一连接只能在完成一个HTTP事务(请求和响应)后 才能处理下一个事务
- HTTP头部巨大且重复 HTTP-> 无状态协议 每一个请求都需要携带HTTP头部 尤其是对于有cookie的头部
- 不支持服务器推送信息 客户端需要获取通知时 只能通过定时器不断拉取消息 浪费带宽 资源
优化手段
- 多个小图合并大图 用js切割 减少请求量 问题:小图更新重新请求大图
- 图片二进制Base64编码 嵌入HTML/CSS文件 减少网络请求次数
- 多个体积较小的使用webpack 打包成体积更大的JS文件
- 统一资源分散到不同域名 提升并发上限 浏览器通常对于统一域名的HTTP连接最大是6
不能优化的地方
- 请求响应模型
- 头部巨大重复
- 并发耗时
- 服务器不能主动推送
兼容HTTP/1.1
- 没有引入新的协议名 实现协议的平滑升级
- 在应用层做了改变 基于TCP协议传输 将HTTP分解成语义和语法两个部分
- 语义层不改变 语法改变
头部压缩
HTTP协议报文组成:Header+Body
Body部分 Content-Encoding 指定压缩方式 Header不能压缩
- 固定字段多 比如 User Agent Accept 等 有必要
压缩
- 大量请求 报文 字段值重复 带宽被冗余数据占用 需要
避免重复性
- 字段是ASCII编码 效率低 有必要改为
二进制编码
HTTP2使用了HPACK
算法来压缩头部
HPACK算法组成部分:
- 静态字典
- 动态字典
- Huffman编码
客户端和服务器两端都会建立和维护字典
用长度较小的索引号表示重复的字符串
再用huffman编码压缩数据 可达到50%-90%
的高压缩率
静态表编码
HTTP/2为高频出现在头部的字符串和字段建立了一张静态表 他是写入到HTTP/2中不会变化的
Index 索引 Header Value 索引对应值 HeaderName 字段名
HTTP/2头部使用二进制编码 用字符串长度分割
动态表编码
生效前提: 必须在同一个连接上 重复传输完全相同的HTTP头部
比如: 第一次发送时头部的user-agent
字段数据有上百个字节 经过哈夫曼编码后 客户端和服务器都会更新自己的动态表 添加新的Index号
下次发送只发送Index号
问题:
动态表大 占用内存大 所以有 http2_max_requests
的配置 限制一个连接能传输的请求数量
请求数量达到上限后 关闭HTTP/2连接来释放内存
二进制帧
HTTP/2将HTTP/1的文本格式改成二进制格式传输数据
极大提高了HTTP传输效率 二进制-> 位运算 高效解析
标志位:携带简单的控制信息
- 头数据结束标志
- 单方向发送结束
- 流的优先级
帧头后四个字节是流标识符 组装信息
帧数据 存放的是HPACK算法压缩过后的HTTP头部和包体
并发传输
HTTP/1.1基于请求-响应模型
同一个连接中 HTTP完成一个事务(请求与响应)才能处理下一个事务
如果发出请求 响应不来 -> 队头阻塞
HTTP/2 Stream 设计 多个Stream复用一条TCP连接 达到并发的效果 提高传输量
- 一个TCP连接包含一个或多个Stream
- Stream里面可以包含一个或者多个Message 对应请求与响应 有由HTTP头部和包体构成
- Message里包含一条或多个Frame Frame是HTTP/2最小单位 二进制压缩
HTTP消息由多个Frame构成 一个Frame可以由多个TCP报文构成
不同Stream的帧可以乱序发送 同一Stream内部的帧必须是严格有序的
客户端和服务器双方都可以建立Stream
客户端奇数 服务器偶数 区分
StreamID 不能复用 只能顺序递增 当Stream ID耗尽时 需要控制帧 GOAWAY
关闭TCP连接
HTTP/2并发发送Stream 时 只需要建立一次TCP连接
HTTP/1.1建立连接很耗时
还可以设置优先级
服务器主动推送资源
在Nginx 中,如果你希望客户端访问 /test.html 时,服务器直接推送 /test.css,那么可以这么配置:
location /test.html {
http2_push /test.css;
}
服务器主动推送的时候 使用的是偶数号Stream 服务器在推送资源时
会通过PUSH_PROMISE
帧传输HTTP头部 并且通过帧中的Promised Stream ID
字段告知客户端 接下来在哪个偶数号Stream中发送包体
总结
- 静态表+哈夫曼编码 压缩体积 建立动态表
- Stream并发 复用TCP连接 可乱序发送
- 可以设置值优先级
- 服务器支持主动推送资源
问题:
- 队头阻塞
HTTP/2基于TCP协议传输数据 TCP是字节流协议
TCP必须确认收到的字节数据 连续完整
才会返回给HTTP应用 如果前一个字节数据没有到达
后收到的字节数据只能存放在内核缓冲区
只有当1字节数据到达时 才能从内核中拿到数据
- 一个丢失 会触发TCP重传
TCP
协议本身问题 -> 拥抱光荣的进化 -> UDP -> HTTP/3