作者:卢满宇, 腾讯后台开发 工程师
商业转载请联系腾讯WeTest获得授权,非商业转载请注明出处。
原文链接:http://wetest.qq.com/lab/view/355.html
WeTest 导读
HTTP/1.X出色地满足互联网的普遍访问需求,但随着互联网的不断发展,其性能越来越成为瓶颈。IETF在2015年发布了HTTP/2标准, 着重于提高HTTP的访问体验, HTTP2优势主要包括: 二进制传输、头部压缩、多路复用和服务器推送(Server Push)。 截止目前, 大部分CDN厂商已经宣布支持HTTP/2,然而”支持”大多省略了服务器推送(ServerPush)特性。估计这和nginx开源版本没有支持Server Push相关。为提供完备的HTTP2能力,腾讯CDN现已完成HTTP/2的Server Push支持,并完成了详细的性能测试。
序言
在介绍Server Push功能之前,先来分析网站的加载过程。图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等总体上是顺序的,等待资源响应的时间减慢了主页面加载速度。并发传输并不能提高串行解析的资源访问体验。
如果服务端接收到客户端主请求,能够“预测”主请求的依赖资源,在响应主请求的同时,主动并发推送依赖资源至客户端。客户端解析主请求响应后,可以”无延时”从本地缓存获取依赖资源, 减少访问延时, 提高访问体验,也加大了链路的并发能力。Server Push正是基于此原理来提高网络体验。
图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/m...)。网页上展示一张世界地图,由400个小图片组成。对比三种访问方式:HTTP/1.1、HTTP/2(无Server Push)和 HTTP/2(Server Push)。Server Push选择推送第150~179个共30个小图。访问性能数据对比如图6所示:可以发现预推送比无推送有一定的性能提升(受网络延时和客户端行为影响,结果存在波动,后文有相应分析)。
图6 demo网站测试
简要介绍了Server Push的优化原理之后,伴随而来的疑问,推送什么资源,怎么去推送,以及比其他优化技术有什么优势?读完本章,这些问题将一一得到解答,文章最后用实例展示Server Push的应用场景和性能优化效果。
一、推送实现
1、标识依赖资源
W3C候选推荐标准(https://www.w3.org/TR/preload/)建议了依赖资源的两种做法:文件内标签和HTTP头部携带, 表示该资源后续会被使用, 可以预请求, 关键字preload修饰这个资源, 写法如下:
a) 静态Link标签法:
b) HTTP头表示法:
Link:
其中rel表明了资源是预加载的,as表明了资源的文件类型。另外,link还可以用nopush修饰,表示浏览器可能已经有该资源缓存,指示有推送能力的服务端不主动推送资源,只有当浏览器先检查到没有缓存,才去指示服务端推送资源,nopush格式写成:
Link: ; rel=preload; as=script;nopush。
2、推送资源
用户访问CDN,主要包括直接访问的边缘节点, 若干中间节点和客户源站,路径中的每层都可以对请求做分析,预测可能的依赖资源,通过插入静态标签或者增加响应头部返回给浏览器。 CDN的推送主要采用头部携带推送信息。
a) 客户端指定推送资源
客户端通过url或者请求头说明需要的资源url,写法如下:
Url:http://http2push.gtimg.com/si...
或者:
GET /simple_push.html HTTP/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节点)可以基于此信息进行资源请求与推送.
3、功能实现
图7所示为CDN的Server Push架构, 基本流程如下:
a) 用户请求到达服务器之后,依赖资源预测模块根据请求头或者配置预测浏览器需要的资源,该推送资源url必须是和主请求是同一host。如果不属于同一host,服务器拒绝推送资源。
b) 服务器通过PUSH_PROMISE桢告诉浏览器准备推送的资源路径,该信息在原主请求流上发送,必须优先主请求响应发送,否则浏览器可能在推送资源到达前已经发起了依赖资源请求,造成重复和浪费.
c) 依赖资源请求模块构造和主请求一样的请求信息,在本地或后端服务器请求推送资源,并主动创建新的HTTP/2请求流,后续服务器就可以发送资源响应,推送资源响应在服务端创建的流上传输,主页面响应在原始流传输。
图7 CDN的Server Push模块改造示意图
CDN节点的推送资源发送顺序在主请求响应之前,如图8所示,主要基于以下因素考量:
d) 推送资源一般是静态的缓存命中率高的资源,如JS、CSS、字体和图片等。这些资源可以从源站预先推送并缓存到CDN节点。相比之下, 主页面变更较多,需要等待网络IO去源站取数据。同时,CDN边缘节点到浏览器的RTT一般是比CDN节点到源站的RTT更短。所以在取到主页面最新响应之前,有充足的时间去推送资源。
e) 资源推送可以探测提高TCP拥塞窗口,窗口逐渐增大,后续可以一次性发送完主页面响应。TCP拥塞窗口对推送影响将在下文第三部分讨论。
f) 在等待主请求响应的网络IO时间期间,推送资源可以是无优先级关系,资源推送优先级对推送影响也将在下文第三部分讨论。
图8 推送时间点位于主页面响应之前
二、Server Push技术对比
1、纵向对比
Server Push相对应没有Server Push的具体提升如下:
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-Delay product, 带宽时延乘积)概念。BDP描述了单位时间内该带宽能传输的数据大小。如果size(HTML) HTTP/1.1中有个资源内联(Resource Inlining)技术,把资源内容拷贝到HTML标签中。比如说
2、横向对比