• 让创新无法想象。咨询热线:022-60709568
  • 关注我们

HTTP/2之服务器推送(Server Push)最佳实践

阅读:904 2019-03-20 16:46:06 来源:新网

wetest导读

http/1.x出色地满足互联网的普遍访问需求,但随着互联网的不断发展,其性能越来越成为瓶颈。ietf在2015年发布了http/2标准,着重于提高http的访问体验,http2优势主要包括:二进制传输、头部压缩、多路复用和服务器推送(serverpush)。截止目前,大部分cdn厂商已经宣布支持http/2,然而”支持”大多省略了服务器推送(serverpush)特性。估计这和nginx开源版本没有支持serverpush相关。为提供完备的http2能力,腾讯cdn现已完成http/2的serverpush支持,并完成了详细的性能测试。

在介绍serverpush功能之前,先来分析网站的加载过程。图1是腾讯课堂(https://ke.qq.com/index.html)的时间瀑布图。

a)首先浏览器请求主页面index.html,服务端响应内容;

b)获取到主页应答,浏览器开始解析主页的html标签,发现构建dom树还需要css,gif,js等资源;

c)发起针对css,gif,js的内容请求;

d)获取并解析js和css等内容,然后继续请求依赖资源。

图1腾讯课堂域名的时间瀑布图

图2是简化的浏览器和服务器的交互过程,横轴代表时间轴,每个虚线区间是1个rtt。红色竖线表示dom加载完成的时间。从图中可知,虽然存在并发传输,但主页index.html和依赖的资源common.css、0684a8bf.css、comb.nowrap.0b772fee.js等总体上是顺序的,等待资源响应的时间减慢了主页面加载速度。并发传输并不能提高串行解析的资源访问体验。

如果服务端接收到客户端主请求,能够“预测”主请求的依赖资源,在响应主请求的同时,主动并发推送依赖资源至客户端。客户端解析主请求响应后,可以”无延时”从本地缓存获取依赖资源,减少访问延时,提高访问体验,也加大了链路的并发能力。serverpush正是基于此原理来提高网络体验。

图3说明了若采用服务端推送的功能,则js/css资源基本可以和html资源同步到达,浏览器可以“无延时”获取js/css资源,客户端的延时最多可以减少一个rtt。

构建一个简单的例子来验证我们的说法。图4所示为simple_push.html代码,页面依赖资源simple_push.js和simple_nopush.js,页面大小均不超过1kb,主要时间消耗在传输延时。如图5所示为推送simple_push.js和不推送simple_nopush.js的效果对比。

图4推送测试html代码

图5不推送&推送的效果对比

我们上线了一个测试demo网站(https://http1.gtimg.cn/push/mypush.html)。网页上展示一张世界地图,由400个小图片组成。对比三种访问方式:http/1.1、http/2(无serverpush)和http/2(serverpush)。serverpush选择推送第150~179个共30个小图。访问性能数据对比如图6所示:可以发现预推送比无推送有一定的性能提升(受网络延时和客户端行为影响,结果存在波动,后文有相应分析)。

图6demo网站测试

简要介绍了serverpush的优化原理之后,伴随而来的疑问,推送什么资源,怎么去推送,以及比其他优化技术有什么优势?读完本章,这些问题将一一得到解答,文章最后用实例展示serverpush的应用场景和性能优化效果。

w3c候选推荐标准(https://www.w3.org/tr/preload/)建议了依赖资源的两种做法:文件内标签和http头部携带,表示该资源后续会被使用,可以预请求,关键字preload修饰这个资源,写法如下:

a)静态link标签法:

b)http头表示法:

link:

用户访问cdn,主要包括直接访问的边缘节点,若干中间节点和客户源站,路径中的每层都可以对请求做分析,预测可能的依赖资源,通过插入静态标签或者增加响应头部返回给浏览器。cdn的推送主要采用头部携带推送信息。

a)客户端指定推送资源

客户端通过url或者请求头说明需要的资源url,写法如下:

url:http://http2push.gtimg.com/simple_push.html?req-push=simple_push.js

或者:

get/simple_push.htmlhttp/1.1

host:http2push.gtimg.com

user-agent:curl/7.49.1

accept:/

x-push-url:simple_push.js

b)cdn节点指定推送资源

cdn节点针对请求资源配置推送资源,基础配置如下:

location~“/simple_push.html$”{

http2_server_push_url/simple_push.js

}

c)源站指定推送资源

通过增加响应头link通知客户端或者cdn节点,后续希望推送的依赖资源,中间具有推送功能的节点(如cdn节点)可以基于此信息进行资源请求与推送.

图7所示为cdn的serverpush架构,基本流程如下:

a)用户请求到达服务器之后,依赖资源预测模块根据请求头或者配置预测浏览器需要的资源,该推送资源url必须是和主请求是同一host。如果不属于同一host,服务器拒绝推送资源。

b)服务器通过push_promise桢告诉浏览器准备推送的资源路径,该信息在原主请求流上发送,必须优先主请求响应发送,否则浏览器可能在推送资源到达前已经发起了依赖资源请求,造成重复和浪费.

c)依赖资源请求模块构造和主请求一样的请求信息,在本地或后端服务器请求推送资源,并主动创建新的http/2请求流,后续服务器就可以发送资源响应,推送资源响应在服务端创建的流上传输,主页面响应在原始流传输。

图7cdn的serverpush模块改造示意图

cdn节点的推送资源发送顺序在主请求响应之前,如图8所示,主要基于以下因素考量:

d)推送资源一般是静态的缓存命中率高的资源,如js、css、字体和图片等。这些资源可以从源站预先推送并缓存到cdn节点。相比之下,主页面变更较多,需要等待网络io去源站取数据。同时,cdn边缘节点到浏览器的rtt一般是比cdn节点到源站的rtt更短。所以在取到主页面最新响应之前,有充足的时间去推送资源。

e)资源推送可以探测提高tcp拥塞窗口,窗口逐渐增大,后续可以一次性发送完主页面响应。tcp拥塞窗口对推送影响将在下文第三部分讨论。

f)在等待主请求响应的网络io时间期间,推送资源可以是无优先级关系,资源推送优先级对推送影响也将在下文第三部分讨论。

图8推送时间点位于主页面响应之前

serverpush相对应没有serverpush的具体提升如下:

a)nopush加载耗时:tnopush=rtt+max(rtt,size(html)/bandwidth)+size(js)/bandwidth

b)push耗时:tpush=rtt+size(html)/bandwidth+size(js)/bw

c)改善效率:diff=1-tpush/tnopush

所以决定推送是否有改善性能的衡量因素是size(html/bandwidth)和rtt谁大。这里引入bdp(bandwidth-delayproduct,带宽时延乘积)概念。bdp描述了单位时间内该带宽能传输的数据大小。如果size(html)

http/1.1中有个资源内联(resourceinlining)技术,把资源内容拷贝到html标签中。比如说

理论上,在带宽足够的环境下,把需要的资源预先推送给客户端,必然能够节省获取资源时间,提升页面访问速度。但由于tcp慢启动、资源加载优先级、浏览器缓存等因素约束,我们在实际测试中发现,serverpush并不总能带来页面加载性能的提升。本节深入探讨下什么场景下的资源适合使用推送。

先复习下tcp慢启动特性:为了防止网络拥塞,tcp将放弃超出拥塞窗口大小的数据。只有当拥塞串口大小的数据传输完成,这个窗口大小将乘以2。如此,能够传输的数据以2的倍数增长。假设拥塞窗口大小为14kb,下图展示了某些情况下,推送比不推送的效率没有提升。

图9tcp慢启动对服务器推送的影响

对比图9中子图1和子图2,子图1虽然预推送了/style.css,但是第一次rtt只传输了/style.css的4kb数据,剩下的16kb在第2个rtt完成。子图1总共需要2个rtt的时间,和子图2没有进行推送用了同样多的时间。子图3使用了3rtt完成了整个网站的传输,这会比没有推送使用更多的时间。

先看下面一个网站例子:

其中1.js会调用2.js文件,3.js和4.js没有调用其他js。

正常没推送的例子加载时间表格会是

图10资源加载优先级的nopush&push效果图

可以看出是因为1.js的加载优先级本应该在3.js和4.js之前,但是预先推送了3.js和4.js,然而1.js需要重新请求,并触发2.js请求,导致等待1rtt接收2.js。所以push比nopush的效率更差。

http/2的请求优先级并不能影响已经在内核发送缓冲区的数据。假设内核发送缓冲区大小比tcp拥塞串口大,导致服务端发送低优先级的数据,存在内核缓冲区。这时,后续有高优先级的响应必须等内核缓冲区空出才能被完成。假设我们访问一个html页面,这个html页面需要回源站取数据,而html需要的静态js资源缓存在cdn边缘节点上。在回源站的等待时间内,把静态js资源发送给浏览器。如果这时候静态js资源很大,塞满了内核发送缓冲区,此时html响应已经到达cdn边缘节点,却不得不等内核缓冲区有空间才能继续发送。等待浏览器解析html内容后续的link请求也会被推迟。

推送浏览器已缓存的资源有可能使的加载时间更长,并且浪费带宽资源。重复推送已缓存的资源,如果没有额外的空闲带宽传输,网络会阻塞它之后正常的请求,导致拖累了整个网站的加载时间。

我们对现网一些网页进行serverpush性能测试,因为推送要求同一个域名下的http/2请求,为了规避非http/2和跨余名带来的干扰,我们设置了代理节点,代理节点完成http/2支持和域名收归,同时配置serverpush功能,观察网页的加载收益。为了准确测试push带来网络时延变化,需要稳定的网络环境,在chrome设置网络环境mytest(rtt:200ms,download:29mb/s,upload:14mb/s),以下的例子都在该网络环境进行测试。

按照前面描述的推送适用场景,用这个腾讯新闻页面(https://news.qq.com/a/20171031/032143.htm)做测试。主请求页面大小为11.6k。可以看出,预先推送js、css、图片等资源给客户端带来的网站性能变快。

图11腾讯新闻页面

图12腾讯新闻页面的无推送&推送对比图

腾讯客服页面不支持https协议。之所以用这个页面是因为该网页页面主请求比较小,并且有js、css触发的次优先级资源请求。我们把这个网页下载下来,并做了一些推送资源域名收归等必要的处理,放在cdn边缘节点做测试。这并没有改变网站的资源和请求顺序,不影响测试效果。

图13是腾讯客服的页面。图14列出腾讯客服页面的所有请求。我们关注下具体几种情况的时间轴:无推送、推送小文件、推送大文件。小文件推送预先在第一个rtt把3个第3层请求才能触发的资源(tcss.ping.js、cdn_djl.js、layer.css)预先推送给浏览器。大文件推送是预先推送了indexbanner.png。

从图14中的无推送和推送3个小文件的子图中,红色虚竖线是指不包括indexbanner.png的加载完成时间,由于3个小文件(尤其是次优先级请求tcss.ping.js)的提取推送,比无推送的时间延迟要短。但是又从无推送和推送大文件的子图中看到,如果无优先级顺序地推送大文件indexbanner.png(782kb)对缩短网站时延无帮助。

图13腾讯客服页面

图14无推送&推送小文件&推送大文件的对比图

虽然本章的测试用例只是庞大互联网网页的冰山一角,文章不能覆盖各种网页场景。但是以下的一些总结建议是有实践意义的。

1、在合适的时机,推送合适的资源,push比nopush带来的网站时延提升是明显的。在网络带宽足够承载推送资源的前提下,我们预先推送浏览器后续请求需要的资源,网站的整体加载时间得到缩短。但是现实网络环境有不一样的延时和带宽。慢速网络环境影响tcp拥塞窗口增长的速度,除非主页面请求足够小,push才能看到效果。

2、即使是错误地实施某些推送策略(比如说推送过大文件),带来的最严重后果,也就是改善不明显。所以建议是多做一些推送策略的尝试,直到把合适的资源在合适的时机把资源推送给浏览器。

3、网站往http/2的环境迁移是个趋势。迁往http/2需要将页面的所有请求尽量收归到同一域名,并且剥离出主页面的资源文件成多个独立的请求。假如你的网站已迁移到http/2,而且网站的主请求不大,但是可能会触发很多资源请求。建议push这些资源。另外不要推送存放在浏览器cookie的资源,这只会浪费带宽。

4、目前的serverpush推送机制没有解决浏览器已经具有资源缓存,而服务器已经推送到网络中,虽然浏览器可以发送rst桢拒绝推送流,但是服务器推送的资源已经在网络中等待浏览器接收。现在已经有一些规范草案(https://tools.ietf.org/html/draft-kazuho-h2-cache-digest-01)尝试用协商缓存摘要来解决问题。

5、cdn中的负载均衡机制可能会将低优先级的推送资源送入到系统缓存区,这会影响高优先级资源的推送效率问题。引入quic替代tcp,可以对缓存中推送资源进行分级,高优先级资源先发。

6、未来或将引入ai分析取代固定推送实现智能化推送。

你可能感兴趣
推荐阅读
推荐商标

HINTOATE

11类

RQVIBEN

11类

哥朗鲨

25类

树叶空间

32类

隆赛达

11类

德浦康

11类

莎莎范

14类

珂珂潘

14类

分享