浅谈http2协议中的新特性

HTTP2是由google研发的SPDY演化而来,相对HTTP1而言,其方法/状态码/URL/标头字段都没有发生任何改变,而是是针对TCP传输效率和性能作了优化,HTTP/1.x协议以换行符作为纯文本的分隔符,而HTTP/2将所有传输的信息分割为更小的消息和帧,并采用二进制格式对它们编码,新的二进制分帧机制改变了客户端与服务器之间交换数据的方式。优化主要包括以下几个方面:

  • 支持完整的请求与响应复用来减少延迟
  • 有效压缩 HTTP 标头字段将协议开销降至最低
  • 增加对请求优先级和服务器推送的支持

HTTP2相关优点及改进

数据流/消息/帧
  • 数据流:已建立的连接内的双向字节流,可以承载一条或多条消息。
  • 消息:与逻辑请求或响应消息对应的完整的一系列帧。
  • 帧:HTTP/2 通信的最小单位,每个帧都包含帧头,至少也会标识出当前帧所属的数据流。

数据流/消息/帧三者之间的关系:
- 所有通信都在一个 TCP 连接上完成,此连接可以承载任意数量的双向数据流。
- 每个数据流都有一个唯一的标识符和可选的优先级信息,用于承载双向消息。
- 每条消息都是一条逻辑 HTTP 消息(例如请求或响应),包含一个或多个帧。
- 帧是最小的通信单位,承载着特定类型的数据,例如 HTTP 标头、消息负载,等等。 来自不同数据流的帧可以交错发送,然后再根据每个帧头的数据流标识符重新组装。
- 数据流依赖关系和权重的组合明确表达了资源优先级,这是一种用于提升浏览性能的关键功能,网络中拥有多种资源类型,它们的依赖关系和权重各不相同。不仅如此,HTTP/2 协议还允许客户端随时更新这些优先级,进一步优化了浏览器性能

frame(帧)- HTTP/2的基石

Frame的基本格式如下:

+-----------------------------------------------+
|                 Length (24)                   |
+---------------+---------------+---------------+
|   Type (8)    |   Flags (8)   |
+-+-------------+---------------+-------------------+
|R|                 Stream Identifier (31)          |
+=+=================================================+
|                   Frame Payload (0...)        ...
+---------------------------------------------------+
  • Length: 表示Frame Payload部分的长度,另外Frame Header的长度是固定的 9 字节(Length + Type + Flags + R + Stream Identifier = 72 bit)。
  • Type: 区分这个 Frame Payload 存储的数据是属于 HTTP Header 还是 HTTP Body;
  • Flags: 共 8 位, 每位都起标记作用。每种不同的 Frame Type 都有不同的 Frame Flags。例如发送最后一个 DATA 类型的 Frame 时,就会将 Flags 最后一位设置 1(flags &= 0x01),表示 END_STREAM,说明这个 Frame 是流的最后一个数据包。
  • R: 保留位。
  • Stream Identifier: 流 ID,当客户端和服务端建立 TCP 链接时,就会先发送一个 Stream ID = 0 的流,用来做些初始化工作。之后客户端和服务端从 1 开始发送请求/响应。
  • Frame Payload:数据部分
  • Frame 由 Frame Header 和 Frame Payload 两部分组成。不论是原来的 HTTP Header 还是 HTTP Body,在 HTTP/2 中,都将这些数据存储到 Frame Payload,组成一个个 Frame,再发送响应/请求
请求/响应多路复用
  • 使用同一个TCP连接并行发送多个请求和响应
  • 消除不必要的延迟,提高网络容量利用率,减少页面加载时间
数据流优先级

为了处理每个数据流之间的传递顺序,HTTP/2 标准允许每个数据流都有一个关联的权重和依赖关系
- 可以向每个数据流分配一个介于 1 至 256 之间的整数,表示权重
- 每个数据流与其他数据流之间可以存在显式依赖关系
- 同一个父节点情况下,权重高的先获取资源。如果有依赖关系,先给父节点分配资源,再给子节点分配资源
- 数据流依赖关系和权重表示传输优先级,而不是要求,因此不能一定保证特定的处理或传输顺序
- 网络中拥有多种资源类型,它们的依赖关系和权重各不相同。不仅如此,HTTP/2 协议还允许客户端随时更新这些优先级,进一步优化了浏览器性能

服务端推送功能:
  • 由客户端缓存
  • 在不同页面之间重用
  • 与其他资源一起复用
  • 由服务器设定优先级
  • 被客户端拒绝
标头压缩

HTTP/2使用HPACK压缩格式压缩请求和响应标头元数据

  • 这种格式支持通过静态 Huffman 代码对传输的标头字段进行编码,从而减小了各个传输的大小。
  • 这种格式要求客户端和服务器同时维护和更新一个包含之前见过的标头字段的索引列表(换句话说,它可以建立一个共享的压缩上下文),此列表随后会用作参考,对之前传输的值进行有效编码
  • HPACK 压缩上下文包含一个静态表和一个动态表:静态表在规范中定义,并提供了一个包含所有连接都可能使用的常用 HTTP 标头字段(例如,有效标头名称)的列表;动态表最初为空,将根据在特定连接内交换的值进行更新
重置功能

在http1中,一个请求发送错误很难中断,需要重新建立tcp链接才能中断,又要话费3次握手处理。而在http2中,我们可以发送一个RST_STREAM帧来实现这种需求。

流量控制

每个http2流都拥有自己公示的流量窗口,可以限制另一端发送数据的大小,流量限制是针对数据帧进行限制的

TLS部署

HTTP/2 协议本身并没有要求它必须基于HTTPS(TLS)部署,但是出于以下三个原因,实际使用中,HTTP/2和HTTPS几乎都是捆绑在一起:

  • HTTP 数据明文传输,数据很容易被中间节点窥视或篡改,HTTPS 可以保证数据传输的保密性、完整性和不被冒充;
  • 正因为 HTTPS 传输的数据对中间节点保密,所以它具有更好的连通性。基于 HTTPS 部署的新协议具有更高的连接成功率;
  • 当前主流浏览器,都只支持基于 HTTPS 部署的 HTTP/2
  • 如果你使用SSL/TLS(以后简称TLS),那么HTTP/2可以提升网站性能。如果你没有,那在使用HTTP/2之前要先支持TLS。这时候使用TLS的性能损耗大致可以被使用HTTP/2的性能提升抵销。
  • 通过减少TLS的性能损失,可以让更多应用使用TLS,从而让用户信息更安全
HTTP1.x的优化反而在http2中会使性能降低

HTTP1.X中针对性能的优化,反而在http2中会影响性能,比如http1.x中会存在以下几方面的优化:
- 分域存储。为了实现并行请求文件,你可能把文件分散到了不同的域里,CDN会自动这么做。但分域存储会影响HTTP/2的性能,建议使用HTTP/2友好的分域存储(建议七),只针对HTTP/1.x用户分域。
- 雪碧图。雪碧图把很多图片拼成一个文件,然后通过代码按需取得每个图片。雪碧图在HTTP/2的环境下没太大用处。
- 拼接的代码文件。与使用雪碧图的原因类似,很多独立的文件也会被弄成一个,然后浏览器再从其中找到并运行需要的文件。
- 插入行内的文件。CSS代码、JavaScript代码,甚至图片等被直接插到HTML文件中的内容。这样可以减少文件传输,代价是初始HTML文件较大。

在采用HTTP/2之前,需要找出应用了这些优化的代码,分析一下它们会不会影响你的应用设计和工作流程。这样在迁移到HTTP/2之后,就可以着手改造它们,甚至撤销某些优化。

http2中的协议协商机制

HTTP Upgrade

为了更方便地部署新协议,HTTP/1.1 引入了 Upgrade 机制,它使得客户端和服务端之间可以借助已有的HTTP语法升级到其它协议

  • 客户端发送请求中带有希望升级到的http版本字段
Connection: Upgrade                # Connection指定的字段需要在多个代理服务器之间传输
Upgrade: protocol-name[/protocol-version]   # Upgrade字段表示希望升级到的http版本
  • 如果服务端不同意升级或者不支持 Upgrade 所列出的协议,直接忽略即可(当成 HTTP/1.1 请求,以 HTTP/1.1 响应)
  • 如果服务端同意升级,那么需要这样响应,HTTP Upgrade 响应的状态码是 101,并且响应正文可以使用新协议定义的数据格式:
HTTP/1.1 101 Switching Protocols
Connection: upgrade
Upgrade: protocol-name[/protocol-version]

HTTP2相对不足

  • 单连接开销比较大。HPACK数据压缩算法会更新两端的查找表。这样可以让连接有状态,而破坏状态就意味着要重建查找表,另外单连接占用内存较多。
  • 你可能不需要SSL。如果你的数据不需要保护,或者已经使用DRM或其他编码进行保护了,那么TLS的安全性对你可能无所谓。
  • 需要抛弃针对HTTP/1.x的优化。HTTP/1.x优化在支持HTTP/2的浏览器中会影响性能,因此可能需要花时间把它们推倒重来。
  • 对下载大文件不利。如果你的应用主要提供大文件下载或者流媒体播放,那可能不想用TLS,而且在只有一个流的情况下,多路复用也体现不出什么优势。

参考文献

猜你喜欢

转载自blog.csdn.net/zdplife/article/details/81432017