解决Web应用程序中长时间运行的查询问题(异步请求)

时间:2009-12-30 09:32:42

标签: web-applications java-ee

这是问题

企业Web应用程序的用户正在执行导致长(非常长)数据库查询(或其他长处理密集型任务)的任务

问题:

  • 请求超时 - 一段时间后用户可能会收到请求超时
  • 会话超时 - 如果不使用会话保持方法,则可以发生会话超时
  • 请求线程锁定
    • 由于请求线程没有返回,它可能会阻止新的请求(如果达到池限制)
    • 在某些应用程序服务器中,服务器的运行状况可能会触发强制重启节点或应用程序(由于长时间运行的请求线程)
  • 如果用户离开页面:
    • 交易未被取消 - 导致无用的处理,没有人会受益于
    • 用户完成后无法返回查看结果
  • 没有进度指示 - 用户只是等待页面刷新

我想出了几个解决方案,但我不确定哪个更好(在所有方面,性能,最佳实践,优雅和可维护性),我想知道您推荐的解决方案是什么,以及如果有一个我错过的解决方案? (可能是的,很多)

糟糕的解决方案:将请求线程用作工作线程,在会话中保存进度状态,让AJAX调用检查另一个并行请求中的状态(在会话中)

妥协解决方案:创建自己的线程池,处理监控线程,工作线程,并通过同步分配事务缓存或持久存储中的状态来处理群集。这会释放请求,但创建应用程序服务器不知道的线程,并且不会在取消部署时关闭。它取决于你以干净的方式关闭线程,并且总有可能你最终会漏掉一些东西。这也不是J2EE的方法。

J2EE解决方案:将JMS用于异步任务,这就是它的用途

Spring解决方案:使用Spring批处理

你在项目中做了什么/做了什么?你知道其他什么解决方案?您认为上面提到的哪一个是赢家?

4 个答案:

答案 0 :(得分:13)

我会把你所谓的“坏解决方案”和“j2ee解决方案”结合起来:

  1. 原始UI线程向“后端”发送异步JMS消息并返回。
  2. 后端接收异步请求并对其进行处理。
  3. 当在后端达到结果(或错误)时,它将返回到控制器层。
  4. 仍在进行AJAX轮询或使用Bayeux / Cometed的UI接收并显示结果。
  5. 技巧是匹配请求/响应对。我会这样做:

    1. 创建一个具有SESSION的“AsyncManagerService”(AMS),甚至可以在APPLICATION范围内创建,以便所有线程都与同一个实例通信。
    2. AMS持有一张地图,其中id为key,任何对象为value。
    3. 创建请求JMS消息时,生成唯一的随机密钥并将其放入消息的jmsCorrelationId以及映射中,并将NULL作为值。也将该ID传递给UI。
    4. 只要地图中的值为NULL ,就让UI线程使用之前生成的ID 轮询AMS。
    5. 当结果准备就绪时,让您的JMS接收器以给定的ID将其放入AMS的地图中。
    6. 下次UI线程轮询地图时,它会收到答案并停止轮询。
    7. 这是干净的,从任何具体领域中抽象出来。纯粹的技术解决方案。

      即使您不喜欢轮询,HTTP在设计上也是无状态的,我认为这种方式轮询只能在明确定义的时间间隔内进行。

      无论如何,我实现了一个完全符合这种模式的系统,运行得很好......

答案 1 :(得分:1)

之前使用的解决方案涉及Jetty Cometd而不是AJAX。 Ajax和Cometd之间的主要区别在于Cometd可以使用更多的pub / sub模型 - 客户端(在这种情况下是Web浏览器)加入发布者(您的应用程序),应用程序将更新和通知推送到Web浏览器适用于Web浏览器对服务器进行持续轮询的ajax模型。即使您没有使用Jetty,也可以使用Cometd解决方案 - 您可以将Jetty jar放入各自Web服务器的lib文件夹中,您应该很高兴。

答案 2 :(得分:1)

向用户显示“您的请求已被接受且需要一小时才能获得更新”的消息

您创建一个存储所有这些事务的表,并在服务器上批量处理这些事务。

用户不必等待很长时间,他很乐意看到这条消息。处理完交易后,您可以发送确认电子邮件。

这是我认为最好的解决方案。

答案 3 :(得分:0)

这些查询运行了多长时间?

如果您谈论会话到期,也许最好让用户不要等待它。对于用户来说,在该查询的选项卡中经常等待20分钟达到峰值总是很烦人。

因此,如果真的是长时间的查询,也许最好改变UI方法并让用户“订购”他(她)稍后回来查看的查询,或者甚至在邮件准备就绪时通过邮件通知。

在这种情况下,我将在DB中准备好查询,并在另一个表中缓存。这意味着,我有一个Web服务器工作一次注册请求,有一个数据库任务或一个单独的进程/服务器根据请求准备查询并通知用户,然后让用户在用户返回时显示它们结果