欢迎你们前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~css
本文由 mariolu 发表于 云+社区专栏
HTTP/1.X出色地知足互联网的广泛访问需求,但随着互联网的不断发展,其性能愈来愈成为瓶颈。IETF在2015年发布了HTTP/2标准, 着重于提升HTTP的访问体验, HTTP2优点主要包括: 二进制传输、头部压缩、多路复用和服务器推送(Server Push)。 截止目前, 大部分CDN厂商已经宣布支持HTTP/2,然而”支持”大多省略了服务器推送(ServerPush)特性。估计这和nginx开源版本没有支持Server Push相关。为提供完备的HTTP2能力,腾讯CDN现已完成HTTP/2的Server Push支持,并完成了详细的性能测试。html
序言nginx
在介绍Server Push功能以前,先来分析网站的加载过程。图1是腾讯课堂(https://ke.qq.com/index.html)...。chrome
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.一、HTTP/2(无Server Push)和 HTTP/2(Server Push)。Server Push选择推送第150~179个共30个小图。访问性能数据对好比图6所示:能够发现预推送比无推送有必定的性能提高(受网络延时和客户端行为影响,结果存在波动,后文有相应分析)。
图6 demo网站测试
简要介绍了Server Push的优化原理以后,伴随而来的疑问,推送什么资源,怎么去推送,以及比其余优化技术有什么优点?读完本章,这些问题将一一获得解答,文章最后用实例展现Server Push的应用场景和性能优化效果。
一
推送实现
一、标识依赖资源
W3C候选推荐标准(https://www.w3.org/TR/preload/)建议了依赖资源的两种作法:文件内<link>标签和HTTP头部携带, 表示该资源后续会被使用, 能够预请求, 关键字preload修饰这个资源, 写法以下:
a) 静态Link标签法:
<link rel="preload" href="push.css" as="style">
b) HTTP头表示法:
Link: <push.css>; rel=preload; as=style
其中rel代表了资源</push.css>是预加载的,as代表了资源的文件类型。另外,link还能够用nopush修饰,表示浏览器可能已经有该资源缓存,指示有推送能力的服务端不主动推送资源,只有当浏览器先检查到没有缓存,才去指示服务端推送资源,nopush格式写成:
Link: </app/script.js>; rel=preload; as=script;nopush。
二、推送资源
用户访问CDN,主要包括直接访问的边缘节点, 若干中间节点和客户源站,路径中的每层均可以对请求作分析,预测可能的依赖资源,经过插入静态<link>标签或者增长响应头部返回给浏览器。 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节点)能够基于此信息进行资源请求与推送.
三、功能实现
图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技术对比
一、纵向对比
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)<BDP,推荐使用push;反之不推荐使用push。
二、横向对比
HTTP/1.1中有个资源内联(Resource Inlining)技术,把资源内容拷贝到HTML标签中。好比说<script>能够装载js的内容,<style>能够装载CSS的内容等。这样JS或者CSS的内容就会在第一个响应中推送给浏览器。虽说它能够作到网站加速。可是它有不少server push没有的缺点。例如资源不能脱离HTML被浏览器单独缓存,而且这个资源在多个url中重复传输多遍。这在多个url共享这个资源的场景是不明智的作法。而使用Server Push,在CDN能适用更丰富的应用场景。
三
使用场景分析
理论上,在带宽足够的环境下,把须要的资源预先推送给客户端,必然可以节省获取资源时间,提高页面访问速度。但因为TCP慢启动、资源加载优先级、浏览器缓存等因素约束,咱们在实际测试中发现,Server Push并不总能带来页面加载性能的提高。本节深刻探讨下什么场景下的资源适合使用推送。
一、TCP慢启动
先复习下TCP慢启动特性:为了防止网络拥塞,TCP将放弃超出拥塞窗口大小的数据。只有当拥塞串口大小的数据传输完成,这个窗口大小将乘以2。如此,可以传输的数据以2的倍数增加。假设拥塞窗口大小为14kB,下图展现了某些状况下,推送比不推送的效率没有提高。
图9 tcp慢启动对服务器推送的影响
对比图9中子图1和子图2,子图1虽然预推送了/style.css,可是第一次RTT只传输了/style.css的4KB数据,剩下的16KB在第2个RTT完成。子图1总共须要2个RTT的时间,和子图2没有进行推送用了一样多的时间。子图3使用了3RTT完成了整个网站的传输,这会比没有推送使用更多的时间。
二、资源加载优先级
先看下面一个网站例子:
<html>
<head>
<script src=”1.js”></script>
<script src=”3.js”></scirpt>
<script src=”4.js”></script>
</head>
<body></body>
</html>
其中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比No Push的效率更差。
三、内核缓冲区
HTTP/2的请求优先级并不能影响已经在内核发送缓冲区的数据。假设内核发送缓冲区大小比TCP拥塞串口大,致使服务端发送低优先级的数据,存在内核缓冲区。这时,后续有高优先级的响应必须等内核缓冲区空出才能被完成。假设咱们访问一个HTML页面,这个HTML页面须要回源站取数据,而HTML须要的静态JS资源缓存在CDN边缘节点上。在回源站的等待时间内,把静态JS资源发送给浏览器。若是这时候静态JS资源很大,塞满了内核发送缓冲区,此时HTML响应已经到达CDN边缘节点,却不得不等内核缓冲区有空间才能继续发送。等待浏览器解析HTML内容后续的link请求也会被推迟。
四、浏览器缓存
推送浏览器已缓存的资源有可能使的加载时间更长,而且浪费带宽资源。重复推送已缓存的资源,若是没有额外的空闲带宽传输,网络会阻塞它以后正常的请求,致使拖累了整个网站的加载时间。
四
网站测试
咱们对现网一些网页进行Server Push性能测试,由于推送要求同一个域名下的HTTP/2请求,为了规避非HTTP/2和跨余名带来的干扰,咱们设置了代理节点,代理节点完成HTTP/2支持和域名收归,同时配置Server Push功能,观察网页的加载收益。为了准确测试Push带来网络时延变化,须要稳定的网络环境,在chrome设置网络环境mytest(RTT: 200ms, Download: 29Mb/s, Upload: 14Mb/s),如下的例子都在该网络环境进行测试。
一、腾讯新闻
按照前面描述的推送适用场景,用这个腾讯新闻页面(https://news.qq.com/a/2017103...)作测试。主请求页面大小为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 无推送&推送小文件&推送大文件的对比图
五
总结
虽然本章的测试用例只是庞大互联网网页的冰山一角,文章不能覆盖各类网页场景。可是如下的一些总结建议是有实践意义的。
一、在合适的时机,推送合适的资源,Push比No Push带来的网站时延提高是明显的。在网络带宽足够承载推送资源的前提下,咱们预先推送浏览器后续请求须要的资源,网站的总体加载时间获得缩短。可是现实网络环境有不同的延时和带宽。慢速网络环境影响TCP拥塞窗口增加的速度,除非主页面请求足够小,Push才能看到效果。
二、即便是错误地实施某些推送策略(好比说推送过大文件),带来的最严重后果,也就是改善不明显。因此建议是多作一些推送策略的尝试,直到把合适的资源在合适的时机把资源推送给浏览器。
三、网站往HTTP/2的环境迁移是个趋势。迁往HTTP/2须要将页面的全部请求尽可能收归到同一域名,而且剥离出主页面的资源文件成多个独立的请求。假如你的网站已迁移到HTTP/2,并且网站的主请求不大,可是可能会触发不少资源请求。建议push这些资源。另外不要推送存放在浏览器cookie的资源,这只会浪费带宽。
四、目前的Server Push推送机制没有解决浏览器已经具备资源缓存,而服务器已经推送到网络中,虽然浏览器能够发送RST桢拒绝推送流,可是服务器推送的资源已经在网络中等待浏览器接收。如今已经有一些规范草案(https://tools.ietf.org/html/d...)尝试用协商缓存摘要来解决问题。
五、CDN中的负载均衡机制可能会将低优先级的推送资源送入到系统缓存区,这会影响高优先级资源的推送效率问题。引入QUIC替代TCP,能够对缓存中推送资源进行分级,高优先级资源先发。
六、将来或将引入AI分析取代固定推送实现智能化推送。
问答
相关阅读
此文已由做者受权腾讯云+社区发布,原文连接:https://cloud.tencent.com/dev...
欢迎你们前往腾讯云+社区或关注云加社区微信公众号(QcloudCommunity),第一时间获取更多海量技术实践干货哦~
海量技术实践经验,尽在云加社区!