@mircode
2016-07-14T15:34:38.000000Z
字数 4188
阅读 1857
BigPipe
BigRender
LazyRender
Quickling
PageCache
试想这样一个场景,一个经常访问的网站,每次打开它的 页面都要要花费6 秒;同时另外一个网站提供了相似的服务,但响应时间只需3秒,那么你会如何选择呢?数据表明,如果用户打开一个网站,等待3~4秒还没有任何反应,他们会变得急躁,焦虑,抱怨,甚至关闭网页并且不再访问,这是非常糟糕的情况。所以,网页加载的速度十分重要,尤其对于拥有遍布全球的 5亿用户的Facebook(全球最大的社交服务网站)这样的大型网站,有着大量并发请求、海量数据等客观情况,速度就成了必须攻克的难题之一。
2010年初的时候,Facebook的前端性能研究小组开始了他们的优化项目,经过了六个月的努力,成功的将个人空间主页面加载耗时由原来的5秒减少为现在的2.5秒。这是一个非常了不起的成就,也给用户来带来了很好的体验。在优化项目中,工程师提出了一种新的页面加载技术,称之为Bigpipe。
传统的页面展示模式,相当于去餐馆吃饭,选好桌子点好菜,然后单子下厨房,大厨开始做菜,所有菜都做好了之后,才给端上来吃。
BigPipe相当于在餐馆吃饭,先选好桌子点好菜(确定用户布局和要展现的模块),单子下到厨房后,多个大厨就可以同时上阵(服务端并发),做好一样端上来一样吃一样(客户端并发)。
原理图
通过对比两种模型,我们可以发现BigPipe方式,可以最大效率的利用CPU并行的特点,加快页面的渲染。服务器通过将页面分块,同时采用多线程的方式并行执行SQL生产数据块复用HTTP请求通道多次向浏览器Flush数据。最终的效果可以做到浏览器边下载边渲染,而不是一直等待服务端页面生成完毕之后,再进行渲染。大大提升了页面的响应时间。
同一个页面,传统模式的时间约为[Sql1+Sql2+Sql3+Sql4+Sql5]+网络传输时间+浏览器渲染时间。采用BigPipe的方式的话,时间约为Max(Sql1,Sql2,Sql3,Sql4,Sql5)+网络时间+浏览器渲染时间。
技术点:长连接+多次truck,后端多线程flush数据块。
首先,我们需要将页面分块。第一块,为整个页面切分的框架。如:
<html>
<head>BigPipe</head>
<body>
<div id="pagelet_1"></div>
<div id="pagelet_2"></div>
<div id="pagelet_3"></div>
<div id="pagelet_4"></div>
</body>
注意:整个框架级别的分块,是一个不闭合的结构,因为如果闭合的话,那么浏览器就会关闭和服务器端的链接。
之后,服务器端并行生成Pagelet内容。如:
// Pagelet1
BigPipe.onPageletArrive(
{
id:"pagelet_1", // 目标DIV的ID
content:"<p>我是pagelet_1</p>", // 需要填充的HTML片段
css:["common.css","pagelet_1.css"],// 依赖的CSS
js:["common.js","pagelet_1.js"], // 依赖的JS
....
}
);
// Pagelet2
.......
// Pagelet3
.......
注意: Pagelet中通常包含,PHP生成的HTML片段,Pagelet依赖的JS和CSS,以及页面框架中DIV的ID
当切分的页面的每一块后台逻辑执行完毕之后,都会向页面返回一个Pagelet。然后,由JS将内容依次填充到对应Pagelet中。
<div id="pagelet_1"></div>
<div id="pagelet_2"></div>
<div id="pagelet_3"></div>
<div id="pagelet_4"></div>
<script>BigPipe.onPageletArrive{...}</script>
<script>BigPipe.onPageletArrive{...}</script>
<script>BigPipe.onPageletArrive{...}</script>
<script>BigPipe.onPageletArrive{...}</script>
BigPipe先输出页面整体布局,然后逐步输出脚本块,一边输出一边执行,将内容渲染回页面布局中。这样可以让服务端的运算、网络传输和浏览器端的渲染变成并行。BigPipe最主要解决的问题是服务端的运算时间,当服务端的运算时间大于 300 ~ 500ms 时才能体现出优势。当服务端响应非常快(小于 100ms),BigPipe 退化为下面要讲的 BigRender。
BigRender属于前端优化的一种手段,通过减少Dom数,加快页面首屏的渲染。这个应该是淘宝率先采用的一种前端优化方案。为什么淘宝没有使用BigPipe呢?看图吧
淘宝后端性能优化的已经很快了,通过BigPipe并行计算已经不能提升多少了。所以,采用减少前端的Dom节点数,来加快网页渲染速度。
先看看效果,下面的截图是美团的页面的截图,通过截图可以看出,上面红色框内的就是首屏的内容,这部分是被渲染好的,下面蓝色框内的只是输出了个占位框,内容时空白的,内容都被保存在一个隐藏的TextArea框内(也可以隐藏到注释等其他内容中,只要不增加Dom节点数量就可以)。当鼠标滑动到下屏幕的时候,开始填充空白区域的内容。
代码如下:
<!--目标容器-->
<article class="br-warp"></article>
<!--通过隐藏HTML内容,减少DOM节点数-->
<textarea class="br-rendered" style="display:none">
article中包含的HTML代码,因为textarea是display:none的元素,
所以浏览器不会渲染textarea。当滚动屏幕时,通过JS将text区域内
容,加载到article中。
</textarea>
<!--通过JS将隐藏的内容,填充的目标容器中-->
<script>
$("article").html($('textarea').html());
</script>
看看Her里面是怎么处理的
【淘宝详情页的BigRender优化与存放大块HTML内容的最佳方式】
【美团首屏BigRender优化】
延迟加载和BigRender类似,只不过需要填充的代码是通过Ajax向后端动态请求回来的并没有将代码隐藏到页面中。这种模式多用于移动端。分段加载可以节省流量,加快页面的响应速度。当用户下滑手机屏幕时候,再动态的发送Ajax去请求所需的页面,尤其是网速交差的情况,使用分段加载,可以很大成度提升用户体验。
<html>
...
<div>首屏代码</div>
<!--加载第二屏内容-->
<script>lazyrender('second');</script>
...
</html>
Facebook提出了一个新名词Ajaxify,顾名思义,就是将传统的POST/GET转换为Ajax请求。优点显而易见,首先减少了不必要的HTML传输,只请求和渲染页面需要更新的部分,这就相应减少了所需传输的内容加快了内容送达至用户的时间。并且也减少了服务端对HTML的不必要的渲染。Facebook也提到了可以减少session的重复load/unload。
将连接通过Ajax形式进行改造
还有最典型的tab签切换
使用Ajax也许不是什么新鲜的新闻,大家拒绝这项技术的原因可能很大程度基于SEO的需求。从网上摘录了这么一段解决方案,如:
// 请求参数key
$isAjax = $_GET["key"];
$con = include 'content.php';
// 如果是ajax请求,返回页面片段
if($isAjax == "ajax"){
echo $con;
// 如果不是ajax请求,则返回完整页面
}else{
$head = include 'head.php';
$foot = include 'head.php';
echo $head + $con + $foot;
}
【Quickling实现原理】
【FaceBook性能优化】
这个就是将经常访问的页面放到缓存中,加快前端的响应速度。这个一般会在后端优化,这里就不在多说了。
看一下FIS+的官网,我们可以发现FIS+针对以上几种性能优化都做了封装。
对照Her的架构图,我们也就很容易理解他的架构了。
【新能优化】