聂永的博客

记录工作/学习的点点滴滴。

Servlet 3.0笔记之异步请求Facebook BigPipe简单模型实现

当前的前端技术明星为Facebook,相继抛出了Quickling,BigPipe等新鲜概念,引领着前端优化的潮流。果然具有大公司的范儿,适时的回馈给整个开发社群,让全体朝前前进了一小步。超赞!
抽空学习了BigPipe,大概相当于分段刷新(flush),强制输出。虽有点旧瓶装新酒的味道,不过前端已经进入了细节为王的阶段,或许在国内已经有人在用,但缺乏分享沟通,或者还不成熟,缺乏关注,缺少重要数据用以论证等。
BigPipe:高性能的“流水线技术”网页,或许可以为需要认知的人们打开一扇窗户。
原文介绍BigPiple:
BigPipe是一个重新设计的基础动态网页服务体系。大体思路是,分解网页成叫做Pagelets的小块,然后通过Web服务器和浏览器建立管道并管理他们在不同阶段的运行。这是类似于大多数现代微处理器的流水线执行过程:多重指令管线通过不同的处理器执行单元,以达到性能的最佳。虽然BigPipe是对现有的服务网络基础过程的重新设计,但它却不需要改变现有的网络浏览器或服务器,它完全使用PHP和JavaScript来实现。
BigPipe在Facebook应用中的工作流程:
1. 请求解析:Web服务器解析和完整性检查的HTTP请求。
2. 数据获取:Web服务器从存储层获取数据。
3. 标记生成:Web服务器生成的响应的HTML标记。
4. 网络传输:响应从Web服务器传送到浏览器。
5. CSS的下载:浏览器下载网页的CSS的要求。
6. DOM树结构和CSS样式:浏览器构造的DOM文档树,然后应用它的CSS规则。
7. JavaScript中下载:浏览器下载网页中JavaScript引用的资源。
8. JavaScript执行:浏览器的网页执行JavaScript代码。
其带来效果较为明显处在于:
这种高度并行系统的最终结果是,多个Pagelets的不同执行阶段同时进行。例如,浏览器可以正在下载三个Pagelets CSS的资源,同时已经显示另一Pagelet内容,与此同时,服务器也在生成新的Pagelet。从用户的角度来看,页面是逐步呈现的。最开始的网页内容会更快的显示,这大大减少了用户的对页面延时的感知。如果您要自己亲眼看到区别,你可以尝试以下连接: 传统模式BigPipe。第一个链接是传统模式单一模式显示页面。第二个链接是BigPipe管道模式的页面。如果您的浏览器版本比较老,网速也很慢,浏览器缓存不佳,哪么两页之间的加截时间差别将更加明显。
值得一提的是BigPipe是从微处理器的流水线中得到启发。然而,他们的流水线过程之间存在一些差异。例如,虽然大多数阶段BigPipe只能操作一次Pagelet,但有时多个Pagelets的CSS和JavaScript下载却可以同时运作,这类似于超标量微处理器。BigPipe另一个重要区别是,我们实现了从并行编程引入的“障碍”概念,所有的Pagelets要完成一个特定阶段,如多个Pagelet显示区,它们都可以进行进一步JavaScript下载和执行。
启用了BigPipe后,服务器端优先输出页面整体布局,浏览器渲染布局;服务器按照串行方式,一段段按优先级顺序,输出片段内容到浏览器端,浏览器执行JS函数,同时可能会同时请求新的JS文件(尽可能不要涉及外部JS),下载特定样式文件(这个时候可以产生并发连接)。浏览器渲染页面单个组件(Pagelet),组件同时加载CSS、JS文件时,不会影响到下一个组件的渲染工作。以往的页面模型在于,浏览器接收所有数据,然后一次性渲染,显示最终结果给客户。
BigPipe涉及到的一些问题,原文没有涉及,来自淘宝的李牧在他的博客中(Facebook让网站速度提升一倍的BigPipe技术分析)提出一些疑问:
脚本阻滞:
         我们知道直接在html中引入外部脚本会造成页面阻滞,即使使用无阻脚本下载的一系列方法引入外部js,但因为JS单线程,当这些脚本load进来之后运行时也会发生阻滞.因为Facebook页面多样,依赖脚本大小不一,这些阻滞会对页面的快速展现造成影响.
        Facebook做法是在ondomready之前只在头部输出一个很小的外部脚本,作为bigpipe的支撑.其余所有模块如果依赖外部脚本(比如某一模块需要日历控件支持),都会在domready事件之后加载.这样做即保证了所有页面所有模块都能在domready前快速形成展现,又可以保证无脚本阻滞的快速的domready时间.
        最快可交互时间:
         domready再快也至少是在页面第一个使用bigpipe输出的chunked的http请求完成之后,对于Facebook来说,这很可能是2秒之后了.那在这2s期间,如果只是页面展现了而不能交互(点击日历无反应),那方案依然不够完美.
         Facebook的做法是,在domready后所依赖脚本已被加载之前,点击行为将会生成一个额外的脚本请求,只将这个点击所依赖的脚步预先load进来.这样保证了最快的可交互时间.Facebook在另一篇文章中对这个技术进行了详细的描述.
         Bigpipe原理简单,实现不复杂,但Facebook却用了1年的时间才形成完备的解决方案.生成方案需要时间,而解决随之而来的脚本阻滞,保障最快交互时间等等问题也会消耗大量时间. 
较为全面的了解了BigPipe,下面使用使用JAVA Servlet 3.0 异步特性,简单模拟BigPipe实现,没有涉及到页面组件单独请求的JS、CSS文件等,仅仅用以演示其过程(最终效果大打折扣)。
我们目标页面大致结构如下,在 The 1KB CSS Grid 生成结构上修改。 moz-screenshot-2
异步Servlet代码:

传统MVC模式在这里貌似去除了,一切在服务器端生成,可借助Freemarker或者静态页面辅助,减轻纯手工拼接HTML代码的麻烦。
生成客户端代码:
moz-screenshot-3_thumb[1].png (800×441)
在Servlet代码中,每输出一段HTML脚本都会迫使当前线程沉睡一定时间,用户在浏览页面时,按照优先级顺序一段一段的输出,用户体验不错。下面的截图,可以略微感知一下。
image
话说若使用BigPipe,须分段刷新,则服务器无法获得最终输出内容长度,只能采用chunked压缩编码格式输出内容,能节省网络流量;但不利于SEO,按照Facebook做法就是,若搜索爬虫访问,就会按照正常方式生成页面。另一方面,BigPipe的应用场景适合计算量大、较为耗时、拥有若干相互独立模块的页面,中小页面不太适合。

posted on 2011-02-22 20:47 nieyong 阅读(2746) 评论(0)  编辑  收藏 所属分类: Servlet3


只有注册用户登录后才能发表评论。


网站导航:
 

公告

所有文章皆为原创,若转载请标明出处,谢谢~

新浪微博,欢迎关注:

导航

<2011年2月>
303112345
6789101112
13141516171819
20212223242526
272812345
6789101112

统计

常用链接

留言簿(58)

随笔分类(130)

随笔档案(151)

个人收藏

最新随笔

搜索

最新评论

阅读排行榜

评论排行榜