集群中Web页面分批输出

字体大小: 中小 标准 ->行高大小: 标准

为了提高性能和减少用户等待时间,我们常用response.flushBuffer方法来分批输出已经转换好的页面。这样内容可以分块逐步显示在网页上,用户不用长时间面对一个空白的页面等待。但在集群系统中,当某个服务器瘫痪从而引起服务迁移情况下,问题就来了,用户可能会看到重复的内容。

这里我们做个实验,写如下一段代码:

      response.setContentType("text/html");
      response.setContentLength(500);

        //不同的机器用不同的颜色和名字

        String color=this.getInitParameter("Color");
        String server=this.getInitParameter("Server");
       
        PrintWriter writer = response.getWriter();
        writer.println("<html><body>");
        writer.println("<h1><font color=\"" + color + "\">Session serviced by tomcat " + server + "</font></h1>");
       
        writer.println("<table aligh=\"center\" border=\"1\">");
        writer.println("<tr><td>Session ID</td><td>");
        writer.println(request.getSession(true).getId());
        writer.println("</td>");
               
        writer.println("</tr><tr><td>Created on</td><td>");
        writer.println(request.getSession().getCreationTime());
        writer.println("</td></tr></table>");
       
        writer.println("<form method=\"POST\" action=\"LongTask\">");
        writer.println("<Input name=\"test\" value=\"\">");
        writer.println("<INPUT TYPE=submit name=\"submit\" value=\"update\">");
        writer.println("</form>");

        //提前把前面的内容输出

        writer.flush();

        Object ob = request.getParameter("test");
        if (ob!=null) {
            request.getSession().setAttribute("test",ob);
            try {
                String time=this.getInitParameter("WaitTime");

                  //这里模拟一个长时间的任务,以便有机会手动把一个机器停掉
                Thread.sleep(Integer.parseInt(time));
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
                 
        }
        writer.println(request.getSession().getAttribute("test"));
        writer.flush();
        writer.close();

        writer.println("</body></html>");

我们用Apache 2.2 + mod_jk + Tomcat 6.0 (In-memory session replication)来架设集群。注意要在httpd.conf的配置中设置Flush选项:

JkWorkersFile conf/workers.properties
JkOptions +FlushPackets
JkMount /examples/jsp/* bal1
JkMount /jkstatus/ stat1

mod_jk的配置

worker.list = bal1,stat1

worker.Tomcat6A.type = ajp13
worker.Tomcat6A.host = localhost
worker.Tomcat6A.port = 8009
worker.Tomcat6A.lbfactor = 10

worker.Tomcat6B.type = ajp13
worker.Tomcat6B.host = localhost
worker.Tomcat6B.port = 8010
worker.Tomcat6B.lbfactor = 10

worker.Tomcat6C.type = ajp13
worker.Tomcat6C.host = localhost

worker.Tomcat6C.port = 8011
worker.Tomcat6C.lbfactor = 10

worker.bal1.type = lb
worker.bal1.sticky_session = 1
worker.bal1.balance_workers = Tomcat6A, Tomcat6B, Tomcat6C

worker.stat1.type = status

我们把上段代码编译成名字为LongTask的servlet,并放到Tomcat自带的例子examples下面。架设三个Tomcat实例在三台机器上。(本文为了方便都放到一台机器localhost上)。当一台机器正在处理请求时,我们手动停掉它。测试结果如下:

图1:发生故障前

图2:发生故障后

除了数据重复外,Session数据也丢失了(原因还未知). 但如果关闭分批输出,则没有这些问题.

此文章由 http://www.ositren.com 收集整理 ,地址为: http://www.ositren.com/htmls/70375.html