HTTP/2是于2015年正式发布的新一代HTTP协议。其在保持HTTP1.x语义、不变动网络基础设施的前提下致力于下降用户可感知延时,提高网络传输效率。本文将从HTTP历史、HTTP/2新特性、升级方法、效果分析四个部分进行介绍。主要涉及了为何咱们须要HTTP/2,HTTP/2能带给咱们什么,如何升级,当前HTTP/2在实际应用的表现怎样四个问题。css
自从1991年Tim Berners-Lee提出HTTP协议的设想到如今已经20多年过去了,在这20多年中Web的发展也是突飞猛进。为了知足不一样时代Web的需求,HTTP协议的更新迭代经历了HTTP0.九、HTTP/1.0、HTTP/1.一、SPDY、HTTP/2几个版本。接下来就这几个版本的HTTP进行简要介绍。 html
HTTP/0.9产生于Web发展的萌芽阶段,是一个简单到只有一条请求行(request line)的HTTP协议。HTTP/0.9只支持GET POST HEAD请求,请求行中不不包含版本号(那时也没有别的版本)。在发起请求、服务器响应(仅支持纯文本,没有响应头)后链接即会关闭。如今流行的Web服务器依然支持HTTP/0.9,由于支持它实在花不了多大代价。前端
GET /index
(响应)
(链接关闭)复制代码
1991-1995年,随着Web浏览器的兴起,人们对Web页面的需求愈来愈多,最典型的就是人们再也不知足于仅包含文本和超连接的超文本文档,而是须要能展示文字、样式、图片等多种媒体类型的数据。所以HTTP/0.9这种简单的传输协议很快就难觉得继。1996年,HTTP-WG发布了了RFC1945,阐述了HTTP/1.0的主要特性:nginx
其实,从如今开始HTTP协议包含的内容已经超出了其名字(超文本传输)所指代的范围,可是这个名字仍然沿用了下来。web
/* 请求 */
GET /rfc/rfc1945.txt HTTP/1.0
User-Agent: CERN-LineMode/2.15 libwww/2.17b3 Accept: */* /* 响应 */
HTTP/1.0 200 OK
ontent-Type: text/plain
Content-Length: 137582
Expires: Thu, 01 Dec 1997 16:00:00 GMT Last-Modified: Wed, 1 May 1996 12:45:26 GMT Server: Apache 0.84复制代码
1997年定义HTTP/1.1的RFC2068正式发布,随后在1999年发布的RFC2616中集合了对HTTP/1.1的改进和更新。总的来说,HTTP/1.1主要明确了以前HTTP/1.0中存在歧义的点,并在此基础上增长了许多新特性:后端
// 请求1
GET /index.html HTTP/1.1
Host: website.org
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_4)... (snip)
// 响应1
HTTP/1.1 200 OK
Server: nginx/1.0.11
Accept-Ranges: bytes // 若是不为none,表明server支持范围请求
Connection: keep-alive // 持久传输,本次请求响应结束后不关闭链接
Content-Type: text/html; charset=utf-8
Cache-Control: max-age=0, no-cache // 缓存控制
Transfer-Encoding: chunked // 传输编码
100 // 当前响应块大小(256Bytes)
<!doctype html> ... (snip) // 响应内容
100 // 另外一块(256Bytes)
... (snip) // 响应内容
0 // 响应分块结束
// 请求2
GET /favicon.ico HTTP/1.1 // 上次请求未关闭链接,本次重用该链接
Range: bytes=0-1023 // 请求字节范围
Connection: close // 告知服务器本次请求响应后关闭链接
// 响应2
HTTP/1.1 200 OK // 第二次请求的响应行
Content-Range: bytes 0-1023/146515 // 响应字节范围//总体字节数
Connection: close // 告知浏览器响应完成或关闭该链接复制代码
从诞生之日到今天,HTTP/1.1以其顽强的生命力伴随一代人见证了Web的繁荣发展。但面对网络中愈来愈多的请求、网页规模的膨胀,HTTP/1.1逐渐开始表现得力不从心,主要表如今如下几个问题上:浏览器
2009年,Google提出了一项实验性的协议SPDY(读音同speedy),旨在开发者不修改当前网站实现的前提下,提升页面加载速度。SPDY提出后,Chrome、Firefox、Opera等主流浏览器前后给出了实现,不少大型网站(如Google、Twitter、Facebook等)分别提供了其对SPDY会话的实现。2012年,HTTP-WG提出了在SPDY基础上构建HTTP/2的草案,2013年给出了第一个对HTTP/2的实现,自此HTTP/二、SPDY并行发展,在客户端和服务器上进行了普遍可靠的测试。2015年,Google 宣布放弃对SPDY的继续支持,标志着HTTP/2正式登上历史舞台。缓存
与HTTP/1.x采用ASCII码明文传输的方式不一样,HTTP/2在服务器和客户端之间采用传输效率更高的二进制的形式。值得一提的是,HTTP/2中报文二进制帧被分为头部帧(Header Frame)和数据帧(Data Frame),这主要是由于HTTP/2为头部字段单独提供了一种压缩方式,可使网络中传输的头部数据下降到最小(见下一节)。 在HTTP/2中,全部数据的传输能够分为链接(Connection)、流(Stream)和帧(Frame)三个层次。与HTTP/1.1中采用的并行链接不一样,HTTP/2在客户端和服务器的整个会话都会复用一条链接。在这个链接中一组完整地请求、响应被称为流。流中的每段数据(头部、数据段)被称为帧。帧是HTTP/2中通讯的最小单位,其中包含了其属于那条流的“身份”信息。
在HTTP/1.x中,一般采用维持多个链接的方式使请求和响应并行发送,由于计算和存储资源的限制,没法经过无限开启新链接(一般上限为六个)的方式完全解决头阻塞问题。在HTTP/2中,全部的数据通讯均在一个链接中完成。每一个数据帧在发送端准备完成后便可发送,无需等待前一个请求的响应。数据接收端则在接到这些乱序发送的数据帧后,再根据每一个帧携带的“身份”,对这些数据进行从新组装,以得到完整地请求或响应数据。HTTP/2中采用的多路复用技术完全解决了头阻塞问题;重复利用了每一组请求、响应之间的链接的网络资源,在下降资源开销的同时,下降了数据传输延时。
安全
前面已经提到,HTTP/1.x会在请求和响应中中重复地携带不常改变的、冗长的头部数据,给网络带来没必要要地负担。HTTP/2除了将ASCII明文转化为二进制帧以提升网络传输的有效性外,还提出了一种专门针对报文头部数据进行压缩的方案——Hpack。其主要思想是,经过重用当前链接中以前发送请求中的头部,仅发送新加或更改的头部信息,以下降报文中头部字段大小。头部压缩的过程以下图所示:bash
在HTTP/2中,请求和响应是能够乱序传输的,所以咱们须要一个机制能够确保哪些被其余响应数据所依赖的或者关键资源被优先传输,以使网页的呈现和使用具备最好的体验。HTTP/2中在流的层面,采用了“优先级树”的形式确保响应数据可以按照依赖关系和优先级顺序来传输。
“优先级树”能够表示成以下图所示的样子。其中子节点所表示的流响应依赖于父节点流,所以父节点流应该被优先传输。在兄弟节点中,被分配权重较大的点应该被分配更多的网络资源,被优先传输。 以下图中(3)所示的“优先级树”中,A,B依赖于C,C依赖于D,所以D应该被优先传输,D传输完后才应该传输C,同理C传输完成后才应该传输A,B,A,B的数据在传输过程当中所占用的网络资源应遵循3:1的关系。
简单来说,Server Push就是容许Server对尚未发出的请求进行响应。以下图所示,在第一个请求中,客户端发出了一条对index.html的请求。经过对index.html的分析,服务器能够推测出其该html的加载还须要style.css和script.js,所以在第一条请求的响应中能够将这些内容一并发送过去,避免了接下来两条请求、响应带来的延迟(RTT, Round-trip Time)。虽然在HTTP/1.x中采用inline的方式,也能够达到相似Server Push的效果,但inline具备如下弊端:
在升级以前首先要确认你当前使用的客户端(浏览器)和服务器均支持了HTTP/2。幸运的是,迄今为止绝大多数浏览器均已对HTTP/2会话提供了支持,目前为止主流的Web服务器最新版本已经能够支持HTTP/2(Nginx ^1.9.5, Apache ^2.4.24 mod_http2)。因此仅须要安装最新版本的服务器便可使用其提供的HTTP/2新特性。须要注意的是,在升级HTTP/2以前要确认服务器支持SSL(支持HTTPS)。HTTP/2自身并不要求必须底层支持SSL,但当服务器不支持SSL时,几乎全部的浏览器会无视HTTP/2链接。
在HTTP/1.x中存在一些用于Web性能提高的“奇技淫巧”,但这些技术可能在HTTP/2中起到相反的做用,所以咱们第一步就是先去除这些可能会妨碍性能的优化。
HTTP/1.x中,通讯两端最多只有六个链接,且是经过区分不一样域名来维持管理的。为了突破这个限制,一般会把请求资源至于不一样的域名下(如 shard1.example.org, shard2.example.org)。而在HTTP/2中,由于不须要新开链接来解决头阻塞问题,因此不须要经过这种方式来增长通讯的链接数。相反的在HTTP/2中采用域名分片会形成如下两个问题:
HTTP/1.x中,为了减小请求多个图片带来的头阻塞问题,一般采用把多个图片拼接成一个大图,而后一个请求将全部图片加载在浏览器中,而后使用CSS技术将所须要的部分按需展现出来。显然的,雪碧图会带来以下问题:
同雪碧图的原理同样,拼接JavaScript、CSS的作法一样是为了减小请求数,以免潜在的头阻塞问题。在HTTP/2中,由于不存在头阻塞问题,所以应该避免这种优化方式带来的一些没必要要地资源的加载。
根据不一样的业务类型和复杂程度,能够选择不一样的升级方式,这里给出三种升级HTTP/2的方式。
一般状况下,一个网站中绝大多数的请求是针对静态资源发起的,所以将静态资源部署到支持HTTP/2的CDN上是一种最方便快捷的升级方法。在这种状况下访问静态资源的请求经过HTTP/2完成,而API访问则经过HTTP/1.x完成。这种方法虽然比较便捷,但因为对服务端HTTP/2的支持失去控制,每每难以充分利用全部已经实现的新特性(如Server Push、优先级控制等)。
反向代理服务器位于客户端和真正的服务器之间,用于对高并发访问的服务器进行负载均衡。在这种状况下头阻塞主要发生在客户端和代理服务器之间的通讯,所以在代理服务器中支持HTTP/2能够消除大部分头阻塞带来的性能问题。而代理服务器和真正的服务器之间仍然采用HTTP/1.x进行通讯。
固然,若是要充分利用HTTP/2带来的性能提高,就须要对全部的服务器启用支持,以保证客户端和服务器之间的全部通讯均采用HTTP/2执行。值得注意的是,如今HTTP/2中的不少特性仍处于实验阶段,不一样的服务器、包可能对不一样特性的支持略有差异,因此在升级以前须要充分阅读文档,确保你须要的特性已经被支持。
Akamai公司给出了一个测试页面用于对比在存在大量请求状况下HTTP/2与HTTP/1.x之间巨大的性能的差别。经过查看HTTP/2请求与HTTP/1.x请求的瀑布流能够发现,HTTP/1.x链接存在严重的头阻塞问题,每一个时刻最多只可能有6条请求在6条链接上执行,而HTTP/2采用多条请求复用一个链接的机制,同一时刻能够接收到的请求数不受链接数的限制,能更加充分地利用网络带宽。在笔者的网络环境下,后者能够将加载一样资源的时间下降50倍。虽然这是一个比较极端的案例,但HTTP/2带来的性能提高可见一斑。
Dropbox提供了其Web服务器从SPDY升级到HTTP/2(Niginx 1.9.15)的过程及分析。下图给出其在升级过程当中,SPDY链接和HTTP/2链接的占比状况,能够看到起其升级过程是在多个服务器中逐步完成的,这给咱们对比升级先后的性能提供了很好地素材。 下图给出了在升级过程当中,请求(ingress)和响应(egress)所占据网络带宽相对于升级前平均值的比。能够看到在切换后,请求所占据网络带宽有了较大幅度的降低(约为原来的一半),这主要是由HTTP/2的头部压缩带来的(虽然SPDY也提供了头部压缩的特性,但因为存在安全问题,一般都不会启用)。而响应占据的网络资源没有太大变化,这主要是由于头部数据在响应中仅占很小一部分。
在升级中也发现了一些存在的问题。经过下图能够看出对于POST请求来讲,平均延时上升了50%。这是因为Nginx 1.9.15对HTTP/2的支持缺陷形成的。具体来说,Nginx会将
SETTINGS.INITIAL_WINDOW_SIZE
字段设为0,这意味着在POST请求在完成TCP握手后并不能当即发送数据,而是须要一个RTT等待服务器将该值提高了一个较大的值后才能开始发送数据(细节参见TCP的慢启动机制)。虽然Nginx 1.11.0修复了这个问题,这依然提示咱们在升级HTTP/2以前,须要充分调研所要采用的服务器和对应的包目前存在的问题,以免升级可能带来的性能降低。
99design网站也对其向HTTP/2迁移作了详细的总结。其迁移工做主要是经过将图片资源部署到支持HTTP/2的CDN上来实现的(升级方法1),衡量性能的指标是页面视觉呈现时间。经过对不一样页面的测试能够发现如下三个现象(关于延时受限和带宽受限的区别能够参考这里):
经过分析得出性能的降低的缘由是升级HTTP/2后前端代码失去了加载资源优先级的控制,从而形成一些影响视觉呈现的关键资源被后置加载致使整个视觉呈现时间的拉长。具体来说,在HTTP/1.x中,先发起请求的资源一般会先加载。所以咱们能够在前端控制资源的加载优先级,将对于视觉呈现较为关键的资源进行优先加载。但在HTTP/2中,响应的返回是乱序的,一些非关键的资源可能会被先返回。当带宽不是限制因素时,这天然不是问题。但当这些非关键资源将带宽耗尽时,关键资源就只好等待带宽释放后才能返回。一言以蔽之,在HTTP/2的使用使得对资源加载顺序的控制权从前端转移到后端了。很显然,其采用的CDN是不支持对流的优先级传输的。这也印证了前文中提到的,使用CDN升级HTTP/2的方式可能会让咱们没法使用HTTP/2的一些特性,甚至会彻底失去控制。
最后,总结一下。
HTTP/1.x中的头阻塞问题会形成链接老是处于等待响应的状态,而未充分利用带宽;HTTP/1.x大量、重复的请求头在网络上传输,使网络负载了很大一部分本须要传输的数据量。
除了解决了上述HTTP/1.x的问题,新的协议还包含了Server Push、流的优先级传输等新特性,使性能获得进一步提高。
目前的主流浏览器均已支持,所以通常状况下只须要升级服务端便可。三种方案:找一个支持HTTP/2的CDN部署网站中的静态资源;升级代理服务器;升级全部服务器。
在存在大量请求、延时受限的环境下,HTTP/2的性能表现相较于HTTP/1.x有明显优点。但考虑到HTTP/2尚年幼,不少特性的实现还未完善,许多特性的表现可能并不是理想。所以在线上升级以前要作充分的测试,确保所采用的实现可以支持你需的特性,其缺陷不会对性能形成重大影响。