HTTP/2 技术调研和性能分析

转载自 | 小米运维(公众号 ID:MI-SRE)
公众号二维码html

HTTP/2 协议简介

HTTP/2 是现行 HTTP 协议(HTTP/1.x)的替代,但它不是重写,HTTP 方法 / 状态码 / 语义都与 HTTP/1.x 同样。不过,HTTP/2 修改了数据格式化(分帧)以及在客户端与服务器间传输的方式。HTTP/2 基于 SPDY3,专一于性能,最大的一个目标是在用户和网站间只用一个链接。前端

HTTP/2 经过支持完整的请求与响应复用来减小延迟,经过有效压缩 HTTP 报头字段将协议开销降至最低,同时增长对请求优先级和服务器推送的支持。java

HTTP/2 协议由如下两个 RFC 组成:nginx

  • RFC 7540 - Hypertext Transfer Protocol Version 2 (HTTP/2); RFC 7541 -
  • HPACK: Header Compression for HTTP/2;

HTTP/2 解决的问题

影响一个 HTTP 网络请求的因素主要有两个:带宽和延迟。在当今的网络状况下,带宽通常再也不是瓶颈,因此咱们主要讨论下延迟。延迟通常由下面几个因素所形成:git

  • 浏览器线头阻塞(Head-Of-Line Blocking):浏览器会由于一些缘由阻塞请求。
  • DNS 查询。
  • 创建链接(Initial connection):HTTP 基于 TCP 协议,TCP 的 3 次握手和慢启动极大增长延迟。

HTTP/1.x 中存在的问题

链接没法复用
链接没法复用会致使每次请求都经历三次握手和慢启动。三次握手在高延迟的场景下影响较明显,慢启动则对文件类大请求影响较大。github

  • HTTP/1.0 传输数据时,每次都须要从新创建链接,增长延迟。
  • HTTP/1.1 虽然加入 keep-alive,能够复用一部分链接,但域名分片等状况下仍然须要创建多个 connection,耗费资源,给服务器带来性能压力。

线头阻塞(Head-Of-Line Blocking)
致使带宽没法被充分利用,以及后续健康请求被阻塞。HOLB 是指在 HTTP/1.x 中,因为服务器必须按接受请求的顺序发送响应的规则限制,那么假设浏览器在一个(tcp)链接上发送了两个请求,那么服务器必须等第一个请求响应完毕才能发送第二个响应——HOLB。虽然如今浏览器容许每一个 origin 创建 6 个 connection,但大量网页动辄几十个或上百个资源,HOLB 依然是主要问题。
协议开销大:
HTTP/1.x 中 header 内容过大(每次请求 header 基本不怎么变化),增长了传输的成本。
安全因素:
在 HTTP 中传输的内容都是明文,客户端和服务端双方没法验证身份。web

HTTP/2 解决的问题

链接复用:
在用户和网站之间只用一个链接,避免后续创建链接过程当中的几个往返和慢启动,同时减小了服务器的资源消耗。算法

没有线头阻塞:
采用新的二进制分帧层的机制,组成消息的帧能够乱序发送,帧到达对端从新组装,不须要等待前面的帧到达后再发送。chrome

报头压缩:
HTTP/2 协议中采用 HPACK 来压缩请求头和响应头,下降协议开销。数据库

更加安全:
当前主流浏览器,都只支持基于 HTTPS 部署的 HTTP/2。

HTTP/2 协议中的新特性

二进制分帧层

HTTP 2.0 性能加强的核心,全在于新增的二进制分帧层,它定义了如何封装 HTTP 消息并在客户端和服务器之间传输,和 HTTP/1.x 对好比下图:
图片描述

这里所谓的 “层”,指的是位于套接字接口与应用可见的高级 HTTP API 之间一个通过优化的新编码机制:HTTP 的语义(包括各类动词、方法、标头)都不受影响,不一样的是传输期间对它们的编码方式变了。HTTP/1.x 协议以换行符做为纯文本的分隔符,而 HTTP/2 将全部传输的信息分割为更小的消息和帧,并采用二进制格式对它们编码。
这样一来,客户端和服务器为了相互理解,都必须使用新的二进制编码机制:HTTP/1.x 客户端没法理解只支持 HTTP/2 的服务器,反之亦然。不过没关系,现有的应用没必要担忧这些变化,由于客户端和服务器会替咱们完成必要的分帧工做。

数据流、消息和帧

新的二进制分帧机制改变了客户端与服务器之间交换数据的方式。 为了说明这个过程,咱们须要了解 HTTP/2 的三个概念:

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

这些概念的关系总结以下:

  • 全部通讯都在一个 TCP 链接上完成,此链接能够承载任意数量的双向数据流。
  • 每一个数据流都有一个惟一的标识符和可选的优先级信息,用于承载双向消息。
  • 每条消息都是一条逻辑 HTTP 消息(例如请求或响应),包含一个或多个帧。

帧是最小的通讯单位,承载着特定类型的数据,例如 HTTP 标头、消息负载等等。 来自不一样 数据流的帧能够交错发送,而后再根据每一个帧头的数据流标识符从新组装,以下图:
图片描述

简言之,HTTP/2 将 HTTP 协议通讯分解为二进制编码帧的交换,这些帧对应着特定数据流中的消息。全部这些都在一个 TCP 链接内复用。这是 HTTP/2 协议全部其余功能和性能优化的基础。

多路复用

在 HTTP/1.x 中,若是客户端要想发起多个并行请求以提高性能,则必须使用多个 TCP 链接。这是 HTTP/1.x 交付模型的直接结果,该模型能够保证每一个链接每次只交付一个响应(响应排队)。更糟糕的是,这种模型也会致使队首阻塞,从而形成底层 TCP 链接的效率低下。
HTTP/2 中新的二进制分帧层突破了这些限制,实现了完整的请求和响应复用:客户端和服务器能够将 HTTP 消息分解为互不依赖的帧,而后交错发送,最后再在另外一端把它们从新组装起来。
图片描述

上图捕捉了同一个链接内并行的多个数据流。客户端正在向服务器传输一个 DATA 帧(数据流 5),与此同时,服务器正向客户端交错发送数据流 1 和数据流 3 的一系列帧。所以,一个链接上同时有三个并行数据流。
将 HTTP 消息分解为独立的帧,交错发送,而后在另外一端从新组装是 HTTP 2 最重要的一项加强。事实上,这个机制会在整个网络技术栈中引起一系列连锁反应,从而带来巨大的性能提高,让咱们能够:

  • 并行交错地发送多个请求,请求之间互不影响。
  • 并行交错地发送多个响应,响应之间互不干扰。
  • 使用一个链接并行发送多个请求和响应。
  • 没必要再为绕过 HTTP/1.x 限制而作不少工做(对 HTTP/1.x 进行优化,例如级联文件、image sprites 和域名分片。
  • 消除没必要要的延迟和提升现有网络容量的利用率,从而减小页面加载时间。
  • 等等…

HTTP/2 中的新二进制分帧层解决了 HTTP/1.x 中存在的队首阻塞问题,也消除了并行处理和发送请求及响应时对多个链接的依赖。结果,应用速度更快、开发更简单、部署成本更低。

请求重置

HTTP 1.1 的有一个缺点是:当一个含有确切值的 Content-Length 的 HTTP 消息被送出以后,你就很难中断它了。固然,一般你能够断开整个 TCP 链接(但也不老是能够这样),但这样致使的代价就是须要经过三次握手来从新创建一个新的 TCP 链接。
一个更好的方案是只终止当前传输的消息并从新发送一个新的。在 HTTP/2 里面,咱们能够经过发送 RST_STREAM 帧来实现这种需求,从而避免浪费带宽和中断已有的链接。

请求优先级

将 HTTP 消息分解为不少独立的帧以后,咱们就能够复用多个数据流中的帧,客户端和服务器交错发送和传输这些帧的顺序就成为关键的性能决定因素。为了作到这一点,HTTP/2 标准容许每一个数据流都有一个关联的权重和依赖关系:

  • 能够向每一个数据流分配一个介于 1 至 256 之间的整数。
  • 每一个数据流与其余数据流之间能够存在显式依赖关系。

数据流依赖关系和权重的组合让客户端能够构建和传递 “优先级树”,代表它倾向于如何接收响应。反过来,服务器可使用此信息经过控制 CPU、内存和其余资源的分配设定数据流处理的优先级,在资源数据可用以后,带宽分配能够确保将高优先级响应以最优方式传输至客户端。
图片描述

如上图,HTTP/2 内的数据流依赖关系经过将另外一个数据流的惟一标识符做为父项引用进行声明;若是忽略标识符,相应数据流将依赖于 “根数据流”。声明数据流依赖关系指出,应尽量先向父数据流分配资源,而后再向其依赖项分配资源。换句话说,“请先处理和传输响应 D,而后再处理和传输响应 C”。

共享相同父项的数据流(即,同级数据流)应按其权重比例分配资源。 例如,若是数据流 A 的权重为 12,其同级数据流 B 的权重为 4,那么要肯定每一个数据流应接收的资源比例,请执行如下操做:
将全部权重求和:4 + 12 = 16
将每一个数据流权重除以总权重:A = 12/16, B = 4/16 所以,数据流 A 应得到四分之三的可用资源,数据流 B 应得到四分之一的可用资源;数据流 B 得到的资源是数据流 A 所获资源的三分之一。 咱们来看一下上图中的其余几个动手示例:顺序为从左到右:

数据流 A 和数据流 B 都没有指定父依赖项,依赖于显式 “根数据流”;A 的权重为 12,B 的权重为 4。所以,根据比例权重:数据流 B 得到的资源是 A 所获资源的三分之一。
   数据流 D 依赖于根数据流;C 依赖于 D。所以,D 应先于 C 得到完整资源分配。权重不重要,由于 C 的依赖关系拥有更高的优先级。
   数据流 D 应先于 C 得到完整资源分配;C 应先于 A 和 B 得到完整资源分配;数据流 B 得到的资源是 A 所获资源的三分之一。
   数据流 D 应先于 E 和 C 得到完整资源分配;E 和 C 应先于 A 和 B 得到相同的资源分配;A 和 B 应基于其权重得到比例分配。

如上面的示例所示,数据流依赖关系和权重的组合明确表达了资源优先级,这是一种用于提高浏览性能的关键功能,网络中拥有多种资源类型,它们的依赖关系和权重各不相同。不只如此,HTTP/2 协议还容许客户端随时更新这些优先级,进一步优化了浏览器性能。换句话说,咱们能够根据用户互动和其余信号更改依赖关系和从新分配权重。

注:数据流依赖关系和权重表示传输优先级,而不是要求,所以不能保证特定的处理或传输顺序。即,客户端没法强制服务器经过数据流优先级以特定顺序处理数据流。 尽管这看起来违反直觉,但倒是一种必要行为。 咱们不但愿在优先级较高的资源受到阻止时,还阻止服务器处理优先级较低的资源。

每一个来源一个链接

有了新的分帧机制后,HTTP/2 再也不依赖多个 TCP 链接去并行复用数据流;每一个数据流都拆分红不少帧,而这些帧能够交错,还能够分别设定优先级。所以,全部 HTTP/2 链接都是永久的,并且仅须要每一个来源一个链接,随之带来诸多性能优点。
大多数 HTTP 传输都是短暂且急促的,而 TCP 则针对长时间的批量数据传输进行了优化。 经过重用相同的链接,HTTP/2 既能够更有效地利用每一个 TCP 链接,也能够显著下降总体协议开销。不只如此,使用更少的链接还能够减小占用的内存和处理空间,也能够缩短完整链接路径(即,客户端、可信中介和源服务器之间的路径)这下降了总体运行成本并提升了网络利用率和容量。 所以,迁移到 HTTP/2 不只能够减小网络延迟,还有助于提升通量和下降运行成本。

在 HTTP/2 RFC 文档中建议实现时客户端不该该在给定的目的地上打开多个 HTTP/2 链接,目的地是由给定的 URI 肯定的 IP 地址及 TCP 端口,或者配置的代理 IP 和端口。固然客户端可使用不相同的服务端名称标识值或者提供不同的 ssl 证书对相同的 IP 地址及 TCP 端口打开多个链接,但应该避免对相同的配置上建立多个链接。
注:链接数量减小对提高 HTTPS 部署的性能来讲是一项特别重要的功能:能够减小开销较大的 TLS 链接数、提高会话重用率,以及从总体上减小所需的客户端和服务器资源。

流量控制

流量控制是一种阻止发送方向接收方发送大量数据的机制,以避免超出后者的需求或处理能力:发送方可能很是繁忙、处于较高的负载之下,也可能仅仅但愿为特定数据流分配固定量的资源。例如,客户端可能请求了一个具备较高优先级的大型视频流,可是用户已经暂停视频,客户端如今但愿暂停或限制从服务器的传输,以避免提取和缓冲没必要要的数据。再好比,一个代理服务器可能具备较快的下游链接和较慢的上游链接,而且也但愿调节下游链接传输数据的速度以匹配上游链接的速度来控制其资源利用率;等等。

不过,因为 HTTP/2 数据流在一个 TCP 链接内复用,TCP 流控制既不够精细,也没法提供必要的应用级 API 来调节各个数据流的传输。为了解决这一问题,HTTP/2 提供了一组简单的构建块,这些构建块容许客户端和服务器实现其本身的数据流和链接级流量控制:

  • 流量控制具备方向性,每一个接收方均可以根据自身须要选择为每一个数据流和整个链接设置任意的窗口大小。
  • 流量控制基于窗口更新帧进行,即接收方广播本身准备接收某个数据流的多少字节,以及对整个链接要接收多少字节。
  • 流量控制窗口大小经过 WINDOW_UPDATE 帧更新,这个字段制定了流 ID 和窗口递增值。
  • 流量控制能够由接收方禁用,包括针对个别的流和针对整个链接。
  • 流量控制基于每一跳进行,而非端到端控制。即,可信中介可使用它来控制资源使用,以及基于自身条件和启发式算法实现资源分配机制。

HTTP/2 未指定任何特定算法来实现流量控制。不过,它提供了简单的构建块并推迟了客户端和服务器实现,能够实现自定义策略来调节资源使用和分配,以及实现新传输能力,同时提高网络应用的实际性能和感知性能。

例如,应用层流量控制容许浏览器仅提取一部分特定资源,经过将数据流流控制窗口减少为零来暂停提取,稍后再行恢复。换句话说,它容许浏览器提取图像预览或首次扫描结果,进行显示并容许其余高优先级提取继续,而后在更关键的资源完成加载后恢复提取。

服务器推送

HTTP/2 新增的另外一个强大的新功能是,服务器能够对一个客户端请求发送多个响应。 换句话说,除了对最初请求的响应外,服务器还能够向客户端推送额外资源(以下图),而无需客户端明确地请求。
图片描述

注:HTTP/2 打破了严格的请求 - 响应语义,支持一对多和服务器发起的推送工做流,在浏览器内外开启了全新的互动可能性。这是一项使能功能,对咱们思考协议、协议用途和使用方式具备重要的长期影响。

为何在浏览器中须要一种此类机制呢?一个典型的网络应用包含多种资源,客户端须要检查服务器提供的文档才能逐个找到它们。那为何不让服务器提早推送这些资源,从而减小额外的延迟时间呢?服务器已经知道客户端下一步要请求什么资源,这时候服务器推送便可派上用场。

事实上,若是在网页中内联过 CSS、JavaScript,或者经过数据 URI 内联过其余资产,那么就已经亲身体验过服务器推送了。对于将资源手动内联到文档中的过程,咱们其实是在将资源推送给客户端,而不是等待客户端请求。使用 HTTP/2,咱们不只能够实现相同结果,还会得到其余性能优点。 推送资源能够进行如下处理:

  • 由客户端缓存
  • 在不一样页面之间重用
  • 与其余资源一块儿复用
  • 由服务器设定优先级
  • 被客户端拒绝

PUSH_PROMISE 101

全部服务器推送数据流都由 PUSH_PROMISE 帧发起,代表了服务器向客户端推送所述资源的意图,而且须要先于请求推送资源的响应数据传输。这种传输顺序很是重要:客户端须要了解服务器打算推送哪些资源,以避免为这些资源建立重复请求。知足此要求的最简单策略是先于父响应(即,DATA 帧)发送全部 PUSH_PROMISE 帧,其中包含所承诺资源的 HTTP 标头。
在客户端接收到 PUSH_PROMISE 帧后,它能够根据自身状况选择拒绝数据流(经过 RST_STREAM 帧)。 (若是资源已经位于缓存中,可能会发生这种状况。) 这是一个相对于 HTTP/1.x 的重要提高。 相比之下,使用资源内联(一种受欢迎的 HTTP/1.x“优化”)等同于 “强制推送”:客户端没法选择拒绝、取消或单独处理内联的资源。
使用 HTTP/2,客户端仍然彻底掌控服务器推送的使用方式。客户端能够限制并行推送的数据流数量;调整初始的流控制窗口以控制在数据流首次打开时推送的数据量;或彻底停用服务器推送。这些优先级在 HTTP/2 链接开始时经过 SETTINGS 帧传输,可能随时更新。
推送的每一个资源都是一个数据流,与内嵌资源不一样,客户端能够对推送的资源逐一复用、设定优先级和处理。 浏览器强制执行的惟一安全限制是,推送的资源必须符合原点相同这一政策:服务器对所提供内容必须具备权威性。

报头压缩

每一个 HTTP 传输都承载一组报头,这些报头说明了传输的资源及其属性。 在 HTTP/1.x 中,此元数据始终以纯文本形式,一般会给每一个传输增长 500–800 字节的开销。若是使用 HTTP Cookie,增长的开销有时会达到上千字节。为了减小此开销和提高性能, HTTP/2 使用 HPACK 压缩格式压缩请求和响应标头元数据,这种格式采用两种简单可是强大的技术:

  1. 这种格式支持经过静态 Huffman 编码对传输的标头字段进行编码,从而减少了各个传输的大小。
  2. 这种格式要求客户端和服务器同时维护和更新一个包含以前见过的标头字段的索引列表(换句话说,它能够创建一个共享的压缩上下文),此列表随后会用做参考,对以前传输的值进行有效编码。

利用 Huffman 编码,能够在传输时对各个值进行压缩,而利用以前传输值的索引列表,咱们能够经过传输索引值的方式对重复值进行编码,索引值可用于有效查询和重构完整的标头键值对。
图片描述

做为一种进一步优化方式,HPACK 压缩上下文包含一个静态表和一个动态表:静态表在规范中定义,并提供了一个包含全部链接均可能使用的经常使用 HTTP 标头字段(例如,有效标头名称)的列表;动态表最初为空,将根据在特定链接内交换的值进行更新。所以,为以前未见过的值采用静态 Huffman 编码,并替换每一侧静态表或动态表中已存在值的索引,能够减少每一个请求的大小。
注:在 HTTP/2 中,请求和响应标头字段的定义保持不变,仅有一些微小的差别:全部标头字段名称均为小写,请求行如今拆分红各个 :method、:scheme、:authority 和 :path 伪标头字段。

至于 HPACK 压缩的详细介绍,请点击这里:HTTP/2 头部压缩技术介绍或者官方 RFC

HTTP/2 协议实际性能测试与分析

为了测试 HTTP/2 对 web 访问的性能提高,本人借助 bbs 产品线的 miui 官方网站,开启了 tengine 的 HTTP/2 的支持,取一周的访问数据与 HTTPS、HTTP 访问数据进行对比分析,详细结果以下:

采集数据量

响应类型分布

请求类别 http https http2
2xx 945144 927482 505702
3xx 243075 258331 681997
4xx 2372 4750 2813
5xx 9 37 88
sum 1190600 1190600 1190600

延迟数据分析

2xx 请求各个响应时间段占比(基于 nginx log 的 request_time 数据)

时间 http https http2
<50ms 79.75% 78.89% 82.60%
<100ms 87.24% 87.47% 89.86%
<150ms 91.12% 91.90% 93.19%
<200ms 92.72% 93.82% 94.54%
<2s 98.99% 99.71% 99.48%

2xx 请求响应时间大于 7 秒的数量 (基于 nginx log 的 request_time 数据)

时间 http https http2
>7s 1960(0.207%) 603(0.065%) 950(0.187%)
>10s 1519(0.160%) 420(0.045%) 638(0.126%)
>30s 594(0.062%) 165(0.017%) 190(0.037%)
>60s 259(0.027%) 104(0.011%) 97(0.019%)

2xx 请求后端响应时间超过 7 秒的数量(基于 nginx log 的 upstream_response_time)

时间 http https http2
>7s 68(0.007%) 88(0.017%) 58(0.006%)

带宽数据分析

301 请求响应大小(基于 nginx 的 request_length 和 bytes_sent 数据)

/static/image/common/miui9.jpg 请求数 总大小(byte) avg(byte) 请求总大小(byte) 请求avg(byte)
http 2722 1460146 536 3194589 1173
https 4695 2618278 415 8019924 1708
http2 16239 6751609 557 1209570 74

200 请求响应大小(基于 nginx log 的 request_length 和 bytes_sent 数据)

/favicon.ico 请求数 响应总大小(byte) 响应avg(byte) 请求总大小(byte) 请求avg(byte)
http 17658 23552229 1413 15300656 866
https 117178 165623779 1413 122356406 1044
http2 80856 105496656 1304 10015908 123

来源分析

客户端分析(基于 nginx log 的 user_agent 数据)

协议 chrome MSIE safari FireFox Crawlers others unknown
http 23.53% 4.26% 3.56% 0.67% 4.01% 15.07% 48.22%
https 79.24% 5.93% 3.67% 1.54% 7.87% 1.42% 0.1%
http2 88.57% 4.93% 1.91% 1.57% 0% 2.9% 0.03%

平台分析(基于 nginx log 的 user_agent 数据)

协议 Android Windows Linux IOS Darwin unknown
http 28.4% 16.07% 0.29% 2.46% 0.12% 51.86%
https 64.85% 24.65% 0.62% 0.54% 0.29% 9.05%
http2 40.06% 57.62% 1.49% 0.44% 0% 0.02%

结论

  1. 典型网络 RTT 下(50~200ms),HTTP/2 对网络延迟性能有必定程度的提高,优于 HTTP/1.x 和 HTTPS。
  2. 在 2xx 和 3xx 请求下 HTTP/2 利用 HPACK 机制压缩响应头和请求头,有效下降了请求和响应的大小,节省了流量,下降了协议消耗。
  3. 目前 HTTP/2 大部分流量来自于 chrome,其对 HTTP/2 的支持性也是最好的。

HTTP/2 协议部署建议

建议一:如今是否须要迁移到 HTTP/2

实现 HTTP/2 很简单,不过,HTTP/2 并非万能的银弹,它只对某些 Web 应用有用,对另一些则没那么有用。

若是你使用 SSL/TLS(之后简称 TLS),那么 HTTP/2 能够提高网站性能。若是你没有,那在使用 HTTP/2 以前要先支持 TLS。这时候,使用 TLS 的性能损耗大体能够被使用 HTTP/2 的性能提高抵销。不过仍是建议你在实际应用以前先测试一下。
HTTP/2 有五大优点:

  1. 每一个服务器只用一个链接。HTTP/2 对每一个服务器只使用一个链接,而不是每一个文件一个链接。这样,就省掉了屡次创建链接的时间,这个时间对 TLS 尤为明显,由于 TLS 链接费时间。
  2. 加速 TLS 交付。HTTP/2 只需一次耗时的 TLS 握手,而且经过一个链接上的多路利用实现最佳性能。HTTP/2 还会压缩首部数据,省掉 HTTP/1.x 时代所需的一些优化工做,好比拼接文件,从而提升缓存利用率。
  3. 简化 Web 应用。使用 HTTP/2 可让 Web 开发者省不少事,由于不用再作那些针对 HTTP/1.x 的优化工做了。
  4. 适合内容混杂的页面。HTTP/2 特别适合混合了 HTML、CSS、JavaScript、图片和有限多媒体的传统页面。浏览器能够优先安排那些重要的文件请求,让页面的关键部分先出现,快出现。
  5. 更安全。经过减小 TLS 的性能损失,可让更多应用使用 TLS,从而让用户信息更安全。

图片描述

相应地,HTTP/2 也有五个不足之处。

  1. 单链接开销比较大。HPACK 数据压缩算法会更新两端的查找表。这样可让链接有状态,而破坏状态就意味着要重建查找表,另外单链接占用内存较多。
  2. 你可能不须要 SSL。若是你的数据不须要保护,或者已经使用 DRM 或其余编码进行保护了,那么 TLS 的安全性对你可能无所谓。
  3. 须要抛弃针对 HTTP/1.x 的优化。HTTP/1.x 优化在支持 HTTP/2 的浏览器中会影响性能,所以可能须要花时间把它们推倒重来。
  4. 对下载大文件不利。若是你的应用主要提供大文件下载或者流媒体播放,那可能不想用 TLS,并且在只有一个流的状况下,多路复用也体现不出什么优点。
  5. 你的客户也许不在意。你的客户极可能不在意他分享的自家猫咪的视频是否受到 TLS 和 HTTP/2 的保护。

总之,一切要看性能。这方面,有好消息也有坏消息。
好消息是 nginx 官方团队在内部对 NGINX 作过测试,结果从理论上可以获得印证:对于要经过典型网络延迟请求的混合内容网页,HTTP/2 的性能好于 HTTP/1.x 和 HTTPS。基于链接的 RTT,结果能够分三种状况。

  • 很低的 RTT(0-20ms):HTTP/1.x、HTTP/2 和 HTTPS 基本无差异。
  • 典型网络 RTT(30-250ms):HTTP/2 比 HTTP/1.x 快,并且它们都比 HTTPS 快。美国两个相邻城市间的 RTT 约为 30 ms,而东西海岸间(约 3000 英里)则约为 70 ms。东京到伦敦间最短路径的 RTT 大约 240 ms。
  • 高 RTT(300ms 及以上):HTTP/1.x 比 HTTP/2 快,后者又比 HTTPS 快。

图片描述

这张图显示了首次渲染的时间,也就是用户第一次在本身屏幕上看到网页内容的时间。这个时间通常认为关系到用户对网站响应速度的感知。

然而,每一个网页都不相同,实际上每一个用户的会话也不同。若是你托管流媒体或提供大文件下载,那你的决定可能不同,甚至相反。

建议二:终止 HTTP/2 和 TLS

终止协议意味着客户端使用指望的协议链接代理服务器,好比 TLS 或 HTTP/2,而后代理服务器再去链接应用服务器、数据库服务器等,但不须要使用相同的协议,以下图所示。
图片描述

使用独立的服务器终止协议意味着使用多服务器架构。多服务器多是多个物理服务器、多个虚拟服务器,或者 AWS 这样的云环境中的多个虚拟服务器实例。多服务器就比单服务器复杂,或者比应用服务器 / 数据库服务器的组合复杂。不过,多服务器架构有不少好处,并且不少流量大的网站也必须用这种架构。

配置了服务器或者虚拟服务器以后,不少事情都成为可能。新服务器能够分担其余服务器的负载,可用于负载平衡、静态文件缓存和其余用途。另外,也可让添加和替换应用服务器或其余服务器更容易。
NGINX 和 NGINX Plus 常常被用来终止 TLS 和 HTTP/2 协议、负载平衡。已有环境没必要改动,除非要把 NGINX 服务器挪到前端。

建议三:找出为 HTTP/1.x 优化的代码

在决定采用 HTTP/2 以前,首先得知道你的代码有哪些是针对 HTTP/1.x 优化过的。大概有四方面的优化。

  1. 分域存储。为了实现并行请求文件,你可能把文件分散到了不一样的域里,CDN 会自动这么作。但分域存储会影响 HTTP/2 的性能,建议使用 HTTP/2 友好的分域存储(建议六),只针对 HTTP/1.x 用户分域。
  2. 雪碧图。雪碧图把不少图片拼成一个文件,而后经过代码按需取得每一个图片。雪碧图在 HTTP/2 的环境下没太大用处,但仍是有点用的。
  3. 拼接的代码文件。与使用雪碧图的缘由相似,不少独立的文件也会被弄成一个,而后浏览器再从其中找到并运行须要的文件。
  4. 插入行内的文件。CSS 代码、JavaScript 代码,甚至图片等被直接插到 HTML 文件中的内容。这样能够减小文件传输,代价是初始 HTML 文件较大。

后面三种优化都涉及把小文件塞进一个较大的文件里,目的是减小新建链接的初始化和握手,这些操做对 TLS 而言很是费时间。

第一种优化即分域存储偏偏相反,强制打开多个链接,目的是并行地从不一样的域获取文件。这两种看似矛盾的技术对于 HTTP/1.x 下的站点却十分有效。然而,要用好这两种技术,必须投入大量时间、精力和资源,用于实现、管理和运维。

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

建议四:部署 HTTP/2

事实上,部署 HTTP/2 并不难。若是使用 NGINX,只要在配置文件中启动相应的协议就能够了。浏览器和服务器会协商采用什么协议,若是浏览器支持 HTTP/2(并且也在使用 TLS),就会使用 HTTP/2。
配置完服务器后,使用支持 HTTP/2 浏览器的用户就会基于 HTTP/2 运行你的应用,而使用旧版本浏览器的用户则会继续使用 HTTP/1.x 运行你的应用,以下图所示。若是你的网站流量很是大,那么应该监测改变先后的性能,对于性能下降的状况,可能就得撤销更改。

注意:使用 HTTP/2 及其单链接以后,NGINX 某些配置的重要性会很明显,特别要注意的是 output_buffers、proxy_buffers 和 ssl_buffer_size 等指令,多测试一下。参见 general configuration notes,特定的 SSL 建议,以及 NGINX 关于 SSL 性能的白皮书。
注意:使用 HTTP/2 传输密文要格外注意。HTTP/2 的 RFC 中有一个长长的列表,列出了要避免的加密套件。建议你本身也搞一个表格,启用 ssl_buffer_size,而后在全部经常使用的浏览器版本下测试你想用的加密套件。

建议五:再谈 HTTP/1.x 优化

你说奇怪不,撤销和修改针对 HTTP/1.x 优化的代码竟然是实现 HTTP/2 最有创意的部分。这里面有几个问题要注意,由于不少事怎么作都是能够的。
在开始运做以前,必须考虑旧版本浏览器用户是否好过。以后,能够采起三个策略撤销和修改 HTTP/1.x 的优化。

  • 什么也不用作。假如你并无针对 HTTP/1.x 作过优化,或者只作过少许优化,那么你几乎什么也不用作,就能够直接迁移到 HTTP/2。
  • 有选择地去作。第二种状况是减小合并某些文件,而不是彻底不合并。好比,牵扯到不少场景的雪碧图就不用动,而被塞得满满的 HTML 可能就要分离出来一些。
  • 彻底撤销 HTTP/1.x 优化。能够再也不作之前作过的任何优化。

缓存仍是普适的。理论上,缓存操做很是适合小文件特别多的状况。可是,小文件多也意味着文件 I/O 多。所以一些相近文件的合并仍是必要的,一方面要考虑工做流程,另外一方面要考虑应用性能。建议多关注一下其余人在过渡到 HTTP/2 过程当中的一些经验。

建议六:实现智能分域

分域存储多是最极端但也最成功的 HTTP/1.x 优化策略。它可以提高 HTTP/1.x 下的应用性能,但在 HTTP/2 之下,其性能提高能够忽略不讲(由于只有一个链接。)
对 HTTP/2 友好的分域,要保证如下两点:

  • 让多个域名解析到同一个 IP。
  • 确保证书包含通配符,以便全部分域名均可以使用,适当的多域证书固然也能够。

有了这些保障,分域还会继续对 HTTP/1.x 有效,即域名仍然能够触发浏览器建立更多链接,但对 HTTP/2 则无效,由于这些域名会被当作同一个域,一个链接就能够访问全部域名了。

HTTP/2 协议客户端和服务支持状况

客户端

PC 端

若是业务提供的是 web 形式的内容,经过浏览器进行访问,因为当前大部分的浏览器都已经支持 HTTP/2 了,因此基本不需进行任何操做,如下为支持 HTTP/2 的浏览器列表:

浏览器 支持HTTP/2 基于的内核 备注
Chrome(49) 支持 从49版本开始支持
IE 11 不支持 win10系统上的IE11支持h2
Edge(14) 支持 从14版本开始支持
Safari(10.1) 支持 从10.1版本开始支持,但都须要OSX10.11+以上系统版本
Firefox(52) 支持 从52版本开始支持
Opera(47.0.2631.55) 支持 从46版本开始支持
搜狗浏览器(7.1.5.25209) 支持
猎豹浏览器(6.0.114.15532) 支持
2345加速浏览器(8.7.0.16013) 支持
百度浏览器(8.7.5000.4962) 不支持 chrome 47
QQ浏览器(9.6.4) 支持 chrome 53
360浏览器(9.1.0.346) 支持 chrome 55
360极速浏览器(8.7.0.306) 支持

移动端

安卓 app 基本采用 JAVA 开发,因为各个应用采用的与服务端通讯的 http 库各不相同,有的是采用 jdk 自带的 httpurlconnection 库和 httpclient 库,有的用的是安卓系统自带的 webview 或者 volley(volley 的 HTTP/2 支持依赖于所使用的 httpstack,默认使用 httpurlconection,但如今也有不少开发者使用第三方的 okhttp 做为 volley 的 httpstack),而有的开发者直接使用的是第三方库相似于 okhttp,netty 等,这些 http 库对 http2.0 的支持状况各不相同。

基于 java 开发的 http 库对 HTTP/2 的支持状况以下:

  • Jetty 从 9.3 版本开始支持,须要依赖于 JDK 8 及以上版本
  • Netty 从 4.1 版本开始支持
  • OkHttp 自然支持
  • Vert.xh 从 3.3.0 版本开始支持
  • Firefly 支持

其它

Golang 的 net/http 库从 Go1.6 版本开始支持 http2,并默认开启

服务端

名称 支持的版本 支持的协商机制
Apache HTTP Server 2.4.17+ h2,h2c ALPN,Upgrade,direct
Apache Tomcat 8.5+ h2,h2c ALPN,Upgrade,direct
Nginx h2,h2c ALPN,NPN,direct
Tengine 2.1.2+ h2 ALPN
Twisted h2 NPN,ALPN
Netty h2,h2c ALPN,NPN,Upgrade,direct

在 HTTP/2 的 github 中维护了一份 HTTP/2 协议的实现列表,更加详细,可供参考。

扩展阅读

1.NPN 和 ALPN

因为现有的 URI 结构正在被 HTTP 1.x 使用而不能被更换,因此 HTTP/2 也必须沿用该结构。所以不得不找到一种方式将使用的协议升级至 HTTP/2,好比能够要求服务器让它做响应时使用 HTTP/2 来替代旧的协议。

HTTP 1.1 自己就制定过 “升级” 的方案:提供一个首部字段,表示容许服务器在收到旧协议请求的同时,能够向客户端发送新协议的响应。但这一方案每每须要花费一次额外的往返通讯来做为升级的代价。
而这一代价是 SPDY 团队不想接受的。由于他们只实现了基于 TLS 的 SPDY,因此他们开发了一个 TLS 的扩展去简化协议的协商。这个扩展被称做 NPN(Next Protocol Negotiation),借助于此,服务器会通知客户端全部它支持的协议,让客户端从中选择一个合适的来进行通信。

IETF 将这个非正式标准 --NPN 进行规范化,从而演变成了 ALPN(Application Layer Protocol Negotiation)。ALPN 会随着 HTTP/2 的应用被推广,而 SPDY 的客户端与服务器则会继续使用 NPN。
因为 NPN 先于 ALPN 诞生,而 ALPN 又经历了一些标准化过程,因此许多早期的 HTTP/2 客户端和服务器在协商 HTTP/2 时会将这二者同时实现。与此同时,考虑到 SPDY 会使用 NPN,而许多服务器又会同时提供 SPDY 以及 HTTP/2,因此在这些服务器上同时支持 ALPN 以及 NPN 显然会成为最理所固然的选择。
ALPN 和 NPN 的主要区别在于:谁来决定通讯协议。在 ALPN 的描述中,是让客户端先发送一个协议优先级列表给服务器,由服务器最终选择一个合适的。而 NPN 则正好相反,客户端有着最终的决定权。

ALPN 扩展的具体资料,能够参考 Jerry Qu 写的这篇博客:谈谈 HTTP/2 的协议协商机制

2.QUIC

QUIC (Quick UDP Internet Connection,快速 UDP 互联网链接) 是一个新的基于 UDP 的多路复用且安全的传输协议,它从头开始设计,且为 HTTP/2 语义作了优化。尽管以 HTTP/2 做为主要的应用协议而构建,然而 QUIC 的构建是基于传输和安全领域数十年的经验的,且实现了使它成为有吸引力的现代通用传输协议的机制。QUIC 提供了等价于
HTTP/2 的多路复用和流控,等价于 TLS 的安全机制,及等价于 TCP 的链接语义、可靠性和拥塞控制。

QUIC 彻底运行于用户空间,它当前做为 Chromium 浏览器的一部分发布给用户,以便于快速的部署和实验。做为基于 UDP 的用户空间传输协议,QUIC 能够作一些因为遗留的客户端和中间设备,或旷日持久的操做系统开发和部署周期的阻碍,而被证实很难在现有的协议中部署的创新。

QUIC 的一个重要目标是经过快速的实验得到更好的传输设计相关的知识。

基于早期的部署的 QUIC 标准化建议为 [draft-hamilton-quic-transport-protocol],[draft-shade-quic-http2-mapping],[draft-iyengar-quic-loss-recovery],和 [draft-thomson-quic-tls]。

更加详细的资料请参考这里:中文文档Chromium 的 QUIC 主页

参考资料

相关文章
相关标签/搜索