当前位置导航:炫浪网>>网络学院>>编程开发>>JAVA教程>>Java进阶

使用Jetty和DWR创建伸缩性Comet程序

Philip McCarthy([email protected])

 异步服务器端事件驱动的Ajax程序很难实现,也很难获得伸缩性。在作者的系列文章里,Plilip McCarthy展示了一个有效的方式:
 Comet模式允许您push数据到客户端,而且Jetty 6的Continuations API让您的Comet程序对大量客户端获得高可伸缩性。您可以方便的同DWR 2使用Comet和Continuations。

 随着Ajax在Web程序开发技术里建立了牢固的位置,出现了几种常见的Ajax使用模式。例如,Ajax通常用于响应用户输入来使用新数据修改局部页面。但有时候,Web程序的用户界面需要根据偶尔的异步服务器端事件来更新,而不需要用户动作 -- 例如,在Ajax聊天程序里显示其他用户输入的一条新消息。由于Web浏览器和服务器间的HTTP连接只能由浏览器建立,服务器不能"推"更改数据到浏览器。

 Ajax程序有两个解决该问题的基本方式:浏览器每隔几秒请求服务器来获得更改,或者服务器维持与浏览器的连接并且传递数据。长连接技术称为Comet。本文展示了怎样使用Jetty服务器引擎和DWR来实现简单而高效的Comet Web程序。

为什么要Comet?
 轮询方式的主要缺点是在大量客户端时产生了大量的传输浪费。每个客户端都必须有规律的请求服务器来获得更改,这是服务器资源的一个重担。最坏的情况是程序很少更新,例如Ajax邮件收件箱。在这种情况下,大量的客户端轮询是多余的,服务器仅仅简单的响应"没有数据"。 可以通过增加轮询间隔时间来减轻服务器负荷,但是这引入了服务器事件和客户端知晓之间的延迟。当然,一个合理的折衷方案可以多数程序适用,并且轮询的工作方式也可以接受。

 然而,对Comet策略的呼唤来自它可感知的高效。客户端不会产生轮询方式特有的传输浪费,一旦事件发生,就会被发布到客户端。但是维持长连接也消耗了服务器资源。当servlet位置持久的请求在等候状态时,servlet独占一个线程。这样传统的servlet引擎就限制了Comet的伸缩性,因为客户端的数量会迅速超过服务器栈可以有效处理的线程的数量。

Jetty 6有什么不同
 Jetty 6设计来处理大量并发连接,它使用Java语言的不堵塞I/O(java.nio)库并且使用优化的输出缓冲架构。Jetty也有一个处理长连接的杀手锏:一个称为Continuations的特性。我将用一个接收请求然后等待两秒发送响应的简单servlet来示范Continuations。然后,我将展示当服务器拥有更多的客户端时将发生什么。最后我将使用Continuations重新实现servlet,并且您将看到它们的不同。

 为了让它更简单,我将限制Jetty servlet引擎为一个单一的请求处理线程。列表1显示了相关的jetty.xml配置。事实上我需要允许在ThreadPool里总共有3个线程:Jetty服务器本身使用一个,HTTP连接器使用一个来监听进来的请求,最后剩一个线程来执行servlet代码。
列表1. 单一servlet线程的Jetty配置

代码

<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN"
  "http://jetty.mortbay.org/configure.dtd">
<Configure id="Server" class="org.mortbay.jetty.server">
  <Set name="ThreadPool">
    <New class="org.mortbay.threadBoundedThreadPool">
      <Set name="minThreads">3</Set>
      <Set name="lowThreads">0</Set>
      <Set name="maxThreads">3</Set>
    </New>
  </Set>
</Configure> 


 下一步,为了模仿异步事件,列表2显示了BlockingServlet的service()方法,它简单的使用Thread.sleep()调用来在完成前暂停2,000毫秒。同时它也在执行开始和结束时输出系统时间。为了帮助区分不同请求的输出,它也把一个请求参数作为标识符记录到日志。
列表2. BlockingServlet

代码 

public class BlockingServlet extends HttpServlet {

  public void service(HttpServletRequest req, HttpServletResponse res) throws java.io.IOException {

    String reqId = req.getParameter("id");

    res.setContentType("text/plain");
    res.getWriter().println("Request: " + reqId + "\tstart:\t" + new Date());
    res.getWriter().flush();

    try {
      Thread.sleep(2000);
    } catch (Exception e) {}

    res.getWriter().println("Request: " + reqId + "\tend:\t" + new Date());
  }
}


[1] [2] [3] [4] [5] 下一页  

相关内容
赞助商链接