从AppEngine的Servlet调用Web服务

时间:2011-09-19 13:41:51

标签: java web-services google-app-engine java-ee scalability

问题:从AppEngine的servlet调用Web服务(0.5-1.5秒/调用)的最佳方法是什么?阻止呼叫在AppEngine环境中是否可扩展?

上下文:我正在使用AppEngine和J2EE开发Web应用程序。应用程序调用Amazon Web服务以获取用户的一些信息。从我的asp.net经验来看,最好的方法就是使用异步http处理程序来防止IIS线程池中的饥饿。对于使用Servlet 2.5规范(3.0 is planned)的J2EE,此功能不可用。

现在我正在考虑使我的控制器(和servlet)线程安全并请求作用域。还有什么我可以做的吗?它甚至是J2EE + AppEngine环境中的问题吗?

编辑:我知道AppEngine和JAX-WS异步调用支持,但我不确定它如何与servlet环境一起使用。据我所知,要完成servlet请求,代码仍应等待异步WS调用完成(回调或其他)。 我假设使用同步原语执行此操作将阻止当前工作线程。

因此,就线程被阻塞而言,为了服务另一个用户请求servlet容器需要在线程池中分配新线程,为堆栈分配新内存并浪费时间进行上下文切换。此外,当我们用完线程池中的线程时,请求可以阻止整个服务器。这些假设基于ASP.Net和IIS线程模型。它们适用于J2EE环境吗?

答案:在研究了Apache和GAE文档之后,似乎线程池中线程的缺乏并不是一个真正的问题。 Apache默认情况下有200个线程用于线程池(相比之下,asp.NET和IIS中有25个)。基于此,我可以推断JVM中的线程相当便宜。

如果确实需要异步处理或者servlet容器将用完线程,则可以重新设计应用程序以通过google channel api发送响应。 工作流程如下:

  1. 向servlet发送同步请求
  2. Servlet为background worker
  3. 创建异步回复和队列任务的通道
  4. Servlet返回对客户端的响应
  5. [提供其他要求]
  6. 后台工作人员通过channel api
  7. 处理并将数据推送到客户端

3 个答案:

答案 0 :(得分:1)

正如您所看到的,servlet不支持使用单个线程来为多个并发请求提供服务 - 每个请求需要一个线程。执行HTTP调用的最佳方法是使用异步urlfetch,并在需要结果时等待该调用完成。这将阻止请求的线程,但没有避免 - 线程专用于当前请求,直到它终止,无论你做什么。

如果您不需要API调用的响应来提供用户的请求,则可以使用任务队列来脱机工作。

答案 1 :(得分:0)

使用fetchAsync是不是可以?

答案 2 :(得分:0)

看看这个,这可能会有所帮助

http://today.java.net/pub/a/today/2006/09/19/asynchronous-jax-ws-web-services.html

我不确定,如果你可以完全复制你在dot net中做的事情,那么你可以做的就是在加载时模拟它

  1. 使用java脚本体onload
  2. 向控制器提交ajax请求
  3. 在控制器中启动异步任务并将响应发送回用户并使用会话令牌来跟踪任务
  4. 您可以轮询控制器(添加另一种方法以请求更新任务,因为您有会话令牌来跟踪任务),直到您收到回复
  5. 您可以执行此操作,等待响应页面或保持轮询控制器的隐藏帧
  6. 获得要查找的回复后,请删除会话令牌
  7. 如果你想这样做将是最好的选择而不是轮询在这种情况下是理想的Reverse Ajax / server push

    编辑:现在我理解你的意思,我认为你可以让你的代码执行异步任务而不是等待来自异步本身的响应,只需将响应发送回用户。我有一个简单的线程,我将开始,但将等待它完成,因为我将响应发送回用户,同时使用会话令牌来跟踪请求

    @Controller
    @RequestMapping("/asyncTest")
    public class AsyncCotroller {
    @RequestMapping(value = "/async.html", method = RequestMethod.GET)
    public ModelAndView dialogController(Model model, HttpServletRequest request) 
    {
       System.err.println("(System.currentTimeMillis()/1000) " + (System.currentTimeMillis()/1000));
       //start a thread (async simulator)
       new Thread(new MyRunnbelImpl()).start();
       //use this attribute to track response
       request.getSession().setAttribute("asyncTaskSessionAttribute", "asyncTaskSessionAttribute");
           //if you look at the print of system out, you will see that it is not waiting on //async task
       System.err.println("(System.currentTimeMillis()/1000) " + (System.currentTimeMillis()/1000));
       return new ModelAndView("test");
    }
    
    class MyRunnbelImpl implements Runnable
    {
    
        @Override
        public void run() 
        {
            try 
            {
                Thread.sleep(5000);
            } catch (InterruptedException e) 
            {
                e.printStackTrace();
            }
        }
    
    }
    }