Bigpipe---FaceBook使用的页面加载技术

BigPipe(FaceBook使用的页面加载技术)

 

理论部分:用户输入域名发送请求到服务端,服务端组合出需要的业务数据返回给客户端,这一过程是现在网页请求最基本传统的方式了。

好处:只做了一次http请求,节省了http连接资源

坏处:如果一次请求数据量过大,会比较慢,并且如果整个业务逻辑部分有一处出问题,很可能导致请求错误返回,整个页面拿不到数据甚至瘫痪。

之后局部刷新技术ajax出现了:客户端可以根据需要去向服务端发不同的请求,加载自己所需要的数据资源,这样请求之间互不影响。

好处:独立请求,可以分开加载数据,是作为分离业务逻辑,模块化的加载的好方式。

坏处:分开加载无疑增加了http请求数,特别是模块分的较多,希望都非常独立的时候,这一样势必是在浪费连接资源;要知道在单次请求数据量很小的情况下,http连接资源可能是更昂贵的代价。

 

可能这个时候为了更加有效利用资源facebook的大牛们用了设计者Changhao Jiang (研究电子电路的博士)设计的技术bigpipe,并应用到实地场景中。

毫无疑问,无论是整个页面一次请求还是ajax都是不优雅的,没有有效利用前端和后端之间的时间差:

这种模式有个缺陷:流程中的操作有着严格的顺序,如果前面的一个操作没有执行结束,后面的操作就不能执行,即操作之间是不能重叠。这样就没有有效利用前后端资源:

服务器生成一个页面的内容时,浏览器是空闲的,显示空白内容;而当浏览器加载渲染页面内容时,服务器又是空闲的, 时间与性能的浪费由此产生。

为了在前后端空闲时,更能有效的并行处理自己要干的事情(前端通过数据渲染页面,后端包装数据传给前端),一个理想的方式就这样诞生了:

前端发了一个请求后,后端根据前端的需要分步拿不同模块的数据,拿好一个立即丢给前端去渲染,这个时候的优势就体现出来:前端渲染后端给的第一部分数据的同时,后端在组装第二部分数据,以此类推,这个并行工作就这样展开了,直到完成所有数据的组装和渲染。对于用户来讲看到的效果就是,打开页面立即就有可看到的内容,不会因为后端数据多大或是页面发出的请求过多,卡死页面的渲染。

 

 

实践demo部分:

 在js群友的帮助下找到一个可参考的测试案例:

http://my.oschina.net/hanshubo/blog/130713

代码如下:在使用队列方面没有仔细斟酌,随便找一个过来,就用了。 


注意一点,就是不要把 PrintWriter 的实例对象拿到多线程里去用,否则会出莫名其妙的异常。 

import java.io.IOException;
import java.io.PrintWriter;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
 
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
public class BigPipeServlet extends HttpServlet {
 
    private static ExecutorService executor = Executors.newFixedThreadPool(50);
 
    public void service(HttpServletRequest request, HttpServletResponse response) throws IOException {
        final ArrayBlockingQueue<String> q = new ArrayBlockingQueue<String>(6);
 
        for (int i = 0; i < 6; i++) {
            final int id = i + 1;
 
            executor.execute(new Runnable() {
                public void run() {
                    try {
                        Thread.sleep((int) (Math.random() * 10000));
                        q.put(pagelet("content" + id, "Wohooo" + id));
                    } catch (InterruptedException e) {
                    }
                }
            });
        }
 
        response.setContentType("text/html;charset=gb2312");
        PrintWriter out = response.getWriter();
        out
                .println("<html><head>"
                        + "<script type=\"text/javascript\">function arrived(id,text) { var b=document.getElementById(id); b.innerHTML = text; }</script>"
                        + "</head><body>" + "<div>Progressive Loading");
        content(out, "content1", "content2", "content3", "content4", "content5", "content6");
        out.println("</div>");
 
        for (int i = 0; i < 6; i++) {
            try {
                out.println(q.take());
                out.flush();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
 
        out.println("</body></html>");
    }
 
    private void content(PrintWriter writer, String... contentIds) {
        for (String id : contentIds) {
            writer.println("<div id=\"" + id + "\">-</div>");
        }
    }
 
    private String pagelet(String id, String content) {
        return "<script>" + "arrived(\"" + id + "\", \"" + content + "\");" + "</script>";
    }
}
 
 

这个案例的服务端是java实现的,有多线程就是有福,不过php也不是不可以,他的模块的扩展能辅助搞定这个问题。

简单讲一下基本做法:

后端创建一个线程池,去维护前端需要的模块数的线程(有几个模块就创建几个线程),然后每个线程response write之后立即flush,这样每个线程的操作就立即返给了前端,

由于http管道只有一个,后端多线程就无法做到多线程并发去flush了,需要堵塞一个个操作或者加锁。做个猜想:如果http管道中也能相应产生多个独立的位置让多线程并发去append到指定的位置,

这样是不是就做到了,多个部分数据可以同时丢给前端。(可能理解有误)

并在前端执行操作。由于不像ajax那样单个请求前后端逻辑完全独立,在bigpipe中,设定好每个模块的顺序就是必须的了。

 struts2 自定义标签实现的
https://www.ibm.com/developerworks/cn/java/j-lo-bigpipe/
 
注:nginx gzip打开时,out.flush无效,怀疑是数据量没达到nginx默认缓存,不会输出,只等到所有数据一起输出,
这样就达不到bipipe的目的了。
 
 
 

成功案例部分:

新浪微博:http://blog.sina.com.cn/s/blog_482611850100xpb1.html

http://v.youku.com/v_show/id_XMzUyOTgyMDY4.html

简单介绍下:

新浪微博提到了用

HTTP协议的chunked编码的方式来处理多个部分

 

 

淘宝:

[浅析]淘宝详情页的BigRender优化的最佳方式

 http://www.csdn.net/article/2011-09-27/304989

 

 

参考:http://www.cnblogs.com/mofish/archive/2011/11/03/2234858.html

 

 

posted on 2013-11-02 15:15  爱的鲁鲁修  阅读(462)  评论(0编辑  收藏  举报