如何在HttpServlet中处理大数据处理?

时间:2016-05-01 08:42:08

标签: java servlets java-ee

在我的Java EE应用程序中,有一个servlet来处理大型数据进程。此过程为数据库中的所有实体(13百万条记录)编制索引,并且至少需要15分钟才能完成。由于服务器处理时间过长,客户端会抛出TIMEOUT异常。

@WebServlet("/index")
public class IndexServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;
    private Logger logger = Logger.getLogger(this.getClass());

    @EJB
    private AddressSession addressSession;

    protected void service(HttpServletRequest request,
            HttpServletResponse response) {

        try {
            addressSession.index();
        } catch (InterruptedException e) {
            logger.error(e);
        }
    }
}

我的问题是如何处理这种情况?我应该使用异步处理吗?

2 个答案:

答案 0 :(得分:2)

对于花费这么长时间的流程,Web界面应该只是一个“作业提交”,它立即确认收到请求并将作业排队等待处理。然后,您将这个“本质上”后端进程与Web层分离。

例如,您不使用http线程池进行后端处理。有一个单独的Executor来处理提交的作业。您可以使用

创建执行程序
ExecutorService executorService = Executors.newFixedThreadPool(10);

然后当请求进来时,您提交的工作如下:

executorService.execute(new Runnable() {
    public void run() {
        // processing
    }
});

现在,如果您还想通过某个Web界面提供有关作业状态的信息,则需要做更多工作。您可能希望为提交的作业分配唯一的ID,并将其与收据确认一起返回。

在这种情况下,由于您使用的是EJB(如果您使用的是EJB 3.1或更高版本),您不需要自己编写Executor程序。您可以在EJB方法上使用Asynchronous注释以声明方式执行此异步处理。

答案 1 :(得分:0)

启用异步支持

正如@ user2494817所说,在这种情况下可以使用异步处理。要在servlet上启用异步处理,请在asyncSupported注释上将参数@WebServlet设置为true:

@WebServlet(urlPatterns = {"/index"}, asyncSupported = true)

使用异步上下文

然后我们需要使用javax.servlet.AsyncContext类,它提供了在服务方法中执行异步处理所需的功能。要获取AsyncContext的实例,请在服务方法的请求对象上调用startAsync()方法。

AsyncContext asyncContext = request.startAsync();

此调用将请求置于异步模式并确保 退出服务方法后未提交响应。必须在阻塞操作完成后在异步上下文中生成响应,或者将请求分派给另一个servlet。

Oracle Java EE 7 Tutorial - 17.12 Asynchronous Processing in Servlets中对此进行了描述。我的解决方案只考虑一个用户,对于其他用例,我们可能需要更复杂的机制。

@WebServlet(urlPatterns = {"/index"}, asyncSupported = true)
public class IndexServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;
    private Logger logger = Logger.getLogger(this.getClass());

    @EJB
    private AddressSession addressSession;

    protected void service(HttpServletRequest request,
            HttpServletResponse response) {

        AsyncContext asyncContext = request.startAsync();
        asyncContext.start(new Runnable() {
            @Override
            public void run() {
                try {
                    addressSession.index();
                } catch (InterruptedException e) {
                    logger.error(e);
                }
        }});
    }
}