在Java中持续处理异步队列的最佳方法是什么?

7
我在架构系统的最后一部分时遇到了困难。目前我正在运行一个Tomcat服务器,其中包含一个响应客户端请求的Servlet。每个请求会将处理消息添加到异步队列中(我可能会使用Spring或更可能使用Amazon SQS通过JMS)。
事件顺序如下:
发送方: 1.接收客户端请求 2.向与此请求相关的DB中添加一些数据,并使用唯一的ID来标识 3.将表示此请求的消息对象添加到消息队列中
接收方: 1.从队列中拉取新的消息对象 2.解开对象并根据消息对象中包含的信息从网站中获取一些信息 3.发送电子邮件提醒 4.更新与该请求相同的唯一ID的DB行,以表明已完成此操作的信息
我很难确定如何正确处理接收方。一方面,我可能可以创建一个简单的Java程序,该程序从命令行启动,选择队列中的每个项目并处理它。那安全吗?让该程序作为另一个线程在Tomcat容器中运行是否更有意义?我不希望这样串行地进行,也就是说,接收端应该能够同时处理多个对象——使用多个线程。我希望这始终运行,24小时不间断。
建立接收端的选项有哪些?

如果有人对我的最终解决方案感兴趣,我使用了Amazon的SQS,并使用Java客户端(利用Spring框架)来轮询队列。当发现消息时,它会处理它并返回等待状态。我可能会添加Quartz线程,目前我只是启动多个进程。 - Ish
我遇到了类似的问题。我想知道Java客户端是如何实现的。希望它不会在无限循环中轮询消息? - TheMonkWhoSoldHisCode
4个回答

3

“一方面,我可能可以创建一个简单的Java程序,在命令行中启动它,然后选择队列中的每个项目并处理它。这样安全吗?”

这有什么不安全的?它很好用。

“把那个程序作为另一个线程在Tomcat容器内运行更有意义吗?”

只有当Tomcat有很多空闲时间来处理后台处理时才是如此。通常,情况是如此 - 你有空闲时间来处理这种处理。

然而,线程并不是最优的。线程共享公共I/O资源,您的后台线程可能会减慢前端速度。

更好的方法是在“80号端口”前端和一个单独的后端进程之间设置JMS队列。后端进程启动,连接到队列,获取并执行请求。如果需要,后端进程可以是多线程的。


3
如果您正在使用JMS,为什么要将任务放入数据库?
您可以使用持久化队列(durable Queue)在JMS中。这样可以保留任务,即使JMS代理死亡,直到它们被确认。您可以拥有冗余代理,以便如果一个代理死亡,第二个代理会自动接管。这可能比使用单个数据库更可靠。

因为我将从目标网站检索一些信息,并将其放置在数据库中的行旁边。这些信息随后需要由客户端在某个时间点检索。我使用数据库并不是为了冗余,而是为了存储数据以供以后检索。 - Ish

1
如果您已经在使用Spring,请查看DefaultMessageListenerContainer。它允许您创建一个POJO消息驱动的Bean。这可以从现有应用程序容器(您的WAR文件)中使用,也可以作为单独的进程使用。

在这种情况下,消费者是持续轮询队列还是以某种方式得到通知? - Ish
我非常确定DefaultMessageListenerContainer会轮询。它的好处是可以将轮询/通知问题隐藏起来,你只需要实现一个JMS MessageListener并完成你需要做的工作即可。 - John Meagher

0

我曾经通过在应用服务器中托管接收器来完成这种事情,我的情况下是Weblogic,但Tomcat也可以。不要轮询队列,使用基于事件的模型。这可以手动编码或者可以是消息驱动的Web服务。如果数据库更新是幂等的,您可以更新数据库并发送电子邮件,然后在队列上发出提交。拥有几个从同一队列读取的线程不是问题。

我使用过各种JMS解决方案,包括Tibco、ActiveMQ(在Apache并购之前)和Joram。Joram是更可靠的开源解决方案,但现在它已成为Apache的一部分,可能已经改变了。


你能解释一下如何实现基于事件的模型吗? - TheMonkWhoSoldHisCode
请查看http://docs.oracle.com/cd/E13222_01/wls/docs90/jms/implement.html#1188496,标题为“异步接收消息”的部分。 - Don Branson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接