写点什么

技术干货:HTTP/2之服务器推送(Server Push)最佳实践

2019 年 10 月 30 日

技术干货:HTTP/2之服务器推送(Server Push)最佳实践

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网站。网页上展示一张世界地图,由 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 推送实现


1、标识依赖资源


W3C候选推荐标准建议了依赖资源的两种做法:文件内< 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。
复制代码


2、推送资源


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


a) 客户端指定推送资源


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


Url:http://http2push.gtimg.com/simple_push.html?req-push=simple_push.js
复制代码


或者:


GET /simple_push.html HTTP/1.1Host: http2push.gtimg.comUser-Agent: curl/7.49.1Accept: */*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 推送时间点位于主页面响应之前


2Server 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)< BDP,推荐使用 push;反之不推荐使用 push。


2、横向对比


HTTP/1.1 中有个资源内联(Resource Inlining)技术,把资源内容拷贝到 HTML 标签中。比如说< script >可以装载 js 的内容,< style >可以装载 CSS 的内容等。这样 JS 或者 CSS 的内容就会在第一个响应中推送给浏览器。虽然说它可以做到网站加速。但是它有很多 server push 没有的缺点。例如资源不能脱离 HTML 被浏览器单独缓存,并且这个资源在多个 url 中重复传输多遍。这在多个 url 共享这个资源的场景是不明智的做法。而使用 Server Push,在 CDN 能适用更丰富的应用场景。


3 使用场景分析


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


1、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 完成了整个网站的传输,这会比没有推送使用更多的时间。


2、资源加载优先级


先看下面一个网站例子:


<html><head><script src=”1.js”></script><script src=”3.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 的效率更差。


3、内核缓冲区


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


4、浏览器缓存


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


4 网站测试


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


1、腾讯新闻


按照前面描述的推送适用场景,用这个腾讯新闻页面做测试。主请求页面大小为 11.6K。可以看出,预先推送 js、css、图片等资源给客户端带来的网站性能变快。



图 11 腾讯新闻页面



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


2、腾讯客服


腾讯客服页面不支持 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 无推送 &推送小文件 &推送大文件的对比图


5 总结


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


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


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


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


4、目前的 Server Push 推送机制没有解决浏览器已经具有资源缓存,而服务器已经推送到网络中,虽然浏览器可以发送 RST 桢拒绝推送流,但是服务器推送的资源已经在网络中等待浏览器接收。现在已经有一些规范草案尝试用协商缓存摘要来解决问题。


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


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


本文转载自公众号云加社区(ID:QcloudCommunity)。


原文链接:


https://mp.weixin.qq.com/s/d11OJ6iepqI2kJ9tczGYBQ


2019 年 10 月 30 日 13:23858

评论

发布
暂无评论
发现更多内容

架构师训练营第一周总结

Geek_2dfa9a

架构师训练营 Week 01

Wancho

在IBM Cloud中运行Fabric

程序那些事

vscode blockchain hyperledger fabric ibm

第一周学习总结

战峰

架构师训练营第一周总结

小树林

第1周 - 食堂就餐卡系统

大海

极客大学架构师训练营

架构师训练营 Week01 学习心得

极客大学架构师训练营

Week1-架构是什么&如何做架构

wyzwlj

极客大学架构师训练营

深入理解JVM垃圾回收机制 - 对象的内存布局

NORTH

深入理解JVM 内存布局 垃圾回收

Week1-Homework

位运算

拾贝

食堂就餐卡系统架构设计文档

朱月俊

食堂就餐卡系统架构设计⽂档

Geek_2dfa9a

食堂就餐卡系统设计

_MISSYOURLOVE

极客大学架构师训练营 第一周命题作业

极客大学架构师训练营--食堂就餐系统架构设计⽂档 -- 第一次作业

John(易筋)

极客时间 极客大学 极客大学架构师训练营

命题作业—第一周

于江水

极客大学架构师训练营

架构师训练营学习总结(week-01)

Justin

架构师训练营第0期-第一周-命题作业1

sljoai

作业

架构师训练营第0期-第一周学习总结

sljoai

作业

使用IBM Blockchain Platform extension开发你的第一个fabric智能合约

程序那些事

区块链 blockchain hyperledger fabric ibm

食堂就餐卡系统设计

mh

系统设计

学习总结—第一周

于江水

极客大学架构师训练营

架构师训练营第一周

Melo

第一周学习总结

胡江涛

极客大学架构师训练营 第一周总结

为啥成为架构师总是少数人?

朱月俊

食堂就餐卡系统设计

dapaul

架构设计 极客大学架构师训练营

小师妹学JavaIO之:Buffer和Buff

程序那些事

io nio 小师妹 buffer buff

架构师训练营作业(week-01)

Justin

食堂就餐卡系统设计

GalaxyCreater

第1周小结

龙7

极客大学架构师训练营

Week 01-作业二:学习总结

dean

2021年,算法还“香”吗?

2021年,算法还“香”吗?

技术干货:HTTP/2之服务器推送(Server Push)最佳实践-InfoQ