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)<BDP,推荐使用push;反之不推荐使用push。
2、横向对比
HTTP/1.1中有个资源内联(Resource Inlining)技术,把资源内容拷贝到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、浏览器缓存