首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

HTTP/2 幕后原理(3)最吸引人的特性

HTTP/2 幕后原理(3)最吸引人的特性

最吸引人的特性HTTP/2 的大多数实用特性归功于 Google 在 SPDY 协议上开展的工作。在 HTTPbis 工作组开始起草 HTTP/2 RFC                的第一个版本时,SPDY 已证明一个主要 HTTP 版本更新切实可行。因为已经部署并开始采用                SPDY,所以有证据表明更新的协议在自然环境下具有更高的性能。
HTTP/2 成功的关键在于,它实现了显著的性能改善,同时保持了 HTTP 范例,以及 HTTP 和 HTTPS 模式。该工作组规定,向 HTTP/2                的迁移必须透明,而且使用者不会受到任何影响。
该协议最吸引人的特性包括:
  • 新升级路径
  • 二进制分帧
  • 请求/响应复用
  • 报头压缩
  • 流优先化
  • 服务器推送
  • 流控制
让我们来查看每个特性。
新升级路径HTTP/2 升级路径与标准路径稍有不同,省去了一些协商。对于基于 HTTP/2                的安全连接,无法通过升级标头请求切换协议,并收到一条让人安心的“101 switching”HTTP 状态。相反,通过使用一个名为应用层协议协商                (ALPN) 的新扩展,客户端向服务器告知它能理解的通信协议(按偏好排序)。服务器然后使用该列表中它也理解的第一个协议作为响应。
SPDY 需要一个安全连接,虽然社区迫于压力会建立这样的连接,但 HTTP/2 规范没有强制要求这么做。但是,所有主要浏览器供应商都仅在 TLS                上实现 HTTP/2,而且不支持不安全的连接。这实际上会迫使 Web 应用程序实现者对所有 HTTP/2 流量使用 TLS(来源: )。curl 用户仍可采用通过                HTTP 升级标头的升级路径,因为它将实现既明确又安全的连接。
二进制协议或许 HTTP/2                的最重要改变是转换为二进制协议。对于开发人员,这可以说是性能增强的焦点。新协议称为二进制分帧层(binary framing layer),它重新设计了编码机制,而没有修改方法、动词和标头的熟悉语义。
最重要的是,所有通信都在单个 TCP                连接上执行,而且该连接在整个对话期间一直处于打开状态。这可能得益于二进制协议将通信分解为帧的方式:这些帧交织在客户端与服务器之间的双向逻辑流中。
连接的拓扑结构正如我提到的,在 HTTP/2 的新范例中,仅在客户端与服务器之间建立了一个 TCP                    连接,而且该连接在交互持续期间一直处于打开状态。在此连接上,消息是通过逻辑流进行传递的。一条消息包含一个完整的帧序列。在经过整理后,这些帧表示一个响应或请求。
图 2 演示了连接组件之间的关系,展示了一个用于建立多个流的连接。在流 1 中,发送了一条请求消息,并返回了相应的响应消息。
图 2. HTTP/2 连接的拓扑结构我们将分别查看每个概念。
连接和流仅与一个对等节点建立一个连接,并在该连接上传输多个流。因为流可以交织,所以可以同时快速的传输多个流。
消息消息是一组帧。在对等节点上重建这些帧时,它们形成一个完整的请求或响应。特定消息的帧在同一个流上发送,这意味着一个请求或响应只能映射到一个可识别的流。
是通信的基本单位。每个帧有一个标头,其中包含帧的长度和类型、一些布尔标志、一个保留位和一个流标识符,如图 3 所示。
图 3. 帧分解点击查看大图
长度length 字段记录帧的大小,它最多可在一个 DATA 帧中携带 224                个字节(约 16 MB),但默认的最大值设置为 214 个字节 (16 KB)。帧大小可以通过协商调得更高一点。
类型type 字段标识帧的用途,可以是以下 10 种类型之一:
  • HEADERS:帧仅包含 HTTP 标头信息。
  • DATA:帧包含消息的所有或部分有效负载。
  • PRIORITY:指定分配给流的重要性。
  • RST_STREAM:错误通知:一个推送承诺遭到拒绝。终止流。
  • SETTINGS:指定连接配置。
  • PUSH_PROMISE:通知一个将资源推送到客户端的意图。
  • PING:检测信号和往返时间。
  • GOAWAY:停止为当前连接生成流的停止通知。
  • WINDOW_UPDATE:用于管理流的流控制。
  • CONTINUATION:用于延续某个标头碎片序列。
参见规范的 11.2                节了解每种帧类型的功能的更多细节。
标志flag 字段是一个布尔值,指定帧的状态信息:
  • DATA 帧可定义两个布尔标志:END_STREAM 和                    PADDED,前者表示数据流结束,后者表示存在填充数据。
  • HEADERS 帧可以将相同的标志指定为 DATA                    帧,并添加两个额外的标志:END_HEADERS 和                    PRIORITY,前者表示标头帧结束,后者表示设置了流优先级。
  • PUSH_PROMISE 帧可以设置 END_HEADERS 和                    PADDED 标志。
所有其他帧类型都无法设置标志。
流标识符流标识符用于跟踪逻辑流的帧成员关系。成员每次仅属于一条消息和流。流可以提供优先级建议,这有助于确定分配给它的网络资源。我稍后会更详细地解释流优先化。
请求/响应复用单一 TCP 连接的问题在于,一次只能发出一个请求,所以客户端必须等到收到响应后才能发出另一个请求。这就是 “线头阻塞”                问题。正如之前讨论的,典型的变通方案是打开多个连接;每个请求一个连接。但是,如果可以将消息分解为更小的独立部分并通过连接发送,此问题就会迎刃而解。
这正是 HTTP/2 希望达到的目标。将消息分解为帧,为每帧分配一个流标识符,然后在一个 TCP                连接上独立发送它们。此技术实现了完全双向的请求和响应消息复用,如下图所示。
图 4. 在 TCP 连接上交织的帧图 4 中的图解显示在一个连接上快速传输了 3 个流。服务器发送两个响应,客户端发送一个请求。
在流 1 中,服务器为一个响应发送 HEADERS 帧;在流 2 中,它为另一个响应发送                HEADERS 帧,随后为两个响应发送 DATA                帧。两个响应按如图所示的方式交织。在服务器发送响应的过程中,客户端发送一条新消息的 HEADERS 和                DATA 帧作为请求。这些帧也与响应帧交织在一起,如下图所示。
图 5. HTTP/2 将请求/响应帧交织在一起所有帧在另一端重新组装,以形成完整的请求或响应消息。
帧交织有许多好处:
  • 所有请求和响应都在一个套接字上发生。
  • 所有响应或请求都无法相互阻塞。
  • 减少了延迟。
  • 提高了页面加载速度。
  • 消除了对 HTTP 1.1 工具的需求。
图 6. 将 HTTP 请求映射到 HTTP/2 帧我们将左侧的一个 HTTP 请求映射到右侧的一个 HEADERS 帧。
在 HEADERS 帧中,设置了两个标志。第一个是 END_STREAM,它设置为                true(由加号表示),表明该帧是给定请求的最后一帧。END_HEADERS 标志也设置为                true,表明该帧是流中最后一个包含标头信息的帧。
HEADERS 帧中的标头属性反映了 HTTP 1.1 请求中设置的属性。因为 HTTP/2 一定要保持 HTTP                协议的语义,所以必须这么做。
接下来,让我们来看看该请求的响应。
将 HTTP                请求映射到帧图 7 的左侧是一个 HTTP 1.1 标头响应。右侧是使用两个 HTTP/2 帧表示的同一个响应:HEADERS 和                DATA。
图 7. 将 HTTP 响应映射到 HTTP/2 帧在 HEADERS 帧中,END_STREAM 表明该帧不是流中的最后一帧,而                END_HEADER 表明它是最后一个包含标头信息的帧。在 DATA                帧中,END_STREAM 表明它是最后一帧。
报头压缩HTTP/2 协议拥有配套的 HPACK。HPACK                的目的是减少客户端请求与服务器响应之间的标头信息重复所导致的开销。报头压缩的实现方式是,要求客户端和服务器都维护之前看见的标头字段的列表。未来在构建引用了已看见标头列表的消息时可以使用此列表。
图 8. 压缩同一个连接上的两个请求的标头在图 8 中的两个请求中,标头信息是重复的。唯一的不同在请求的资源上(已采用黄色突出显示)。HPACK                报头压缩可以在这里派上用场。在第一个请求后,它仅需发送与前一个标头的不同之处,因为服务器保留着以前看见的标头的列表。除非设置了标头值,否则会假设后续请求拥有与之前的请求相同的标头值。
流优先化消息帧通过流进行发送。每个流都分配了一个优先级,用于确定它的处理顺序,以及它将收到的资源量。
将该优先级输入到给定流的标头帧或优先级帧中,优先级可以是 0 到 256 之间的任何数字。
可以定义依赖关系,允许在一个资源之前加载另一个资源。也可以将优先级组合到一个依赖树中,让开发人员对分配给每个流的重要性有更多控制权。
图 9. 用于流优先化的依赖树在图 9 中,字母表示流标识符,数字表示分配给每个流的权重。树的根是流 A,首先会向它分配资源,然后才向依赖它的流 B 和 C 分配资源。为流 B                分配了 40% 的可用资源,流 C 收到了 60% 的可用资源。流 C 是流 D 和 E 的父流,二者分别从其父流收到相同的资源配额。
流优先级仅是对服务器的建议,可以动态更改或完全忽略。在起草 HTTP/2                协议的过程中,工作组认为允许客户端强迫服务器遵守特定资源分配是不对的。相反,服务器可以自由调整优先级,使其与自己的能力匹配。
服务器推送服务器推送使服务器能预测客户端请求的资源需求。然后,在完成请求处理之前,它可以将这些资源发送到客户端。
要了解服务器推送的好处,可以考虑一个包含图像和其他依赖项(比如 CSS 和 JavaScript                文件)的网页。客户端发出一个针对该网页的请求。服务器然后分析所请求的页面,确定呈现它所需的资源,并主动将这些资源发送到客户端的缓存。在执行所有这些操作的同时,服务器仍在处理原始网页请求。客户端收到原始网页请求的响应时,它需要的资源已经位于缓存中。
那么 HTTP/2 如何管理服务器推送而不会让客户端过载?针对希望发送的每个资源,服务器会发送一个 PUSH_PROMISE                帧,但客户端可通过发送 RST_STREAM 帧作为响应来拒绝推送(例如,如果浏览器的缓存中已包含该资源)。重要的是所有                PUSH_PROMISE 都在响应数据之前发送,所以客户端知道它需要请求哪些资源。
流控制流控制管理数据的传输,使发送者不会让接收者不堪重负。它允许接收者停止或减少发送的数据量。例如,参阅一个提供点播视频的流媒体服务。观看者观看一个视频流时,服务器正在向客户端发送数据。如果视频暂停,客户端会通知服务器停止发送视频数据,以避免耗尽它的缓存。
打开一个连接后,服务器和客户端会立即交换 SETTINGS 帧来确定流控制窗口的大小。默认情况下,该大小设置为约 65                KB,但可通过发出一个 WINDOW_UPDATE 帧为流控制设置不同的大小。
返回列表