在这种情况下,JMS主题是否足够?或者我应该去别处看看?

时间:2011-09-20 23:58:33

标签: java jms

有一个控制实体和几个“工人”实体。控制实体从工作实体请求某些数据,它们将以自己的方式获取和返回。

由于控制实体可以不知道工作者实体(并且可以在任何时候添加/删除工作实体),因此将JMS提供者放在它们之间听起来是个好主意。至少这是假设。

由于它是一对多关系(控制器 - >工作者),因此JMS主题将是正确的解决方案。但是,由于控制实体依赖于工作者的返回值,请求/回复功能也会很好(在某处,我读到了TopicRequester,但我似乎无法找到一个有效的例子)。请求/回复是典型的队列功能。

为了尝试在请求/回复中使用主题,我创建了两个JMS topis:requestresponse。控制器发布到request主题并订阅response主题。每个工作人员都订阅了request主题并发布到response主题。为了匹配请求和响应,控制器将使用过滤器(使用会话ID作为值)订阅response主题的每个请求。工作人员发布到response主题的消息具有与之关联的会话ID。

现在这不是一个解决方案(而是使用JMS作为锤子并将问题(以及更多)作为指甲处理)。 JMS在这种情况下是一个解决方案吗?或者我有其他解决方案吗?

3 个答案:

答案 0 :(得分:0)

你的方法对我有意义。我认为消息传递系统可以工作。我认为使用主题是错误的。看一下Enterprise Service Bus的wiki页面。它比你需要的要复杂一些,但是你的用例的基本思想是你有一个能够从一个队列中读取,进行一些处理并将处理过的数据添加回另一个队列的工人。

主题的问题在于,所有工作人员将同时收到消息并且他们将独立地处理该消息。听起来你只需要一个工人一次处理每个请求。我认为你把它作为一个主题,所以不同类型的工作者也可以听同一个队列,只响应某些请求。为此,您最好只为每种类型的工作创建一个新队列。您可以成对使用它们,因此您有一个work_a_request队列和work_a_response队列。或者,如果您的控制器能够确定数据的响应类型,它们都可以写入单个响应队列。

如果您尚未选择Message Queue供应商,我建议RabbitMQ因为它易于设置,易于添加新队列(特别是动态)并且具有非常好的弹簧支持(尽管大多数主要)消息系统有弹簧支持,你可能甚至不使用spring。

我也不确定你在做什么过滤器。如果您确保向工作人员发送的消息包含完成工作所需的所有信息,并且响应消息包含控制器完成处理所需的所有信息,我认为您不需要它们。

答案 1 :(得分:0)

我只想使用两个JMS队列。

第一个是所有请求继续进行的。工作人员将听取队列,并以自己的方式在自己的时间处理它们。

完成后,他们会将请求与响应捆绑在一起,并将其放在另一个队列中,以便最终处理。这样,提交过程就不需要保留请求,只需遵循整个过程即可。最后一个进程将侦听第二个队列,并适当地处理请求/响应对。

如果消息不需要可靠,或者不需要实际进程跨越JVM或机器,那么这一切都可以通过单个进程和标准java线程(例如BlockingQueues和ExecutorServices)来完成。

如果需要累积相关的响应,那么您需要捕获所需的任何分组数据,并使Queue 2监听过程累积结果。或者您可以将结果保存在数据库中。

例如,如果您知道您的工作集有五个元素,则可以使用该信息排队请求(5个中的1个,5个中的2个等)。每个完成后,最终进程可以更新数据库,计算元素。当它看到所有部分都已完成(按任何顺序)时,它会将结果标记为完成。稍后您将对一些未完成的未完成作业进行一些审计过程扫描(可能是其中一条消息错误),因此您可以更好地处理它们。或者原始处理器可以将请求写入单独的“这一个坏了”队列以进行缓解和重新提交。

如果将JMS与事务一起使用,如果其中一个处理器发生故障,事务将回滚并且消息将保留在队列中以供其中一个幸存的处理器处理,这是JMS的另一个优势。

这种处理的技巧是尝试用消息推送状态,或者外化它并发送对状态的引用,从而使每个组件有效地无状态。这有助于扩展和可靠性,因为任何组件都可能出现故障(除了灾难性的JMS故障,当然也是如此),并且当您解决问题并重新启动它们时,只需从停止的位置开始接收。

如果您处于请求/响应模式(例如需要响应的servlet),您可以使用Servlet 3.0异步servlet轻松地将事物保留,或者您可以将本地对象放在内部地图上,键入使用诸如会话ID之类的东西,然后在该键中使用Object.wait()。然后,您的队列2侦听器将获得响应,完成处理,然后使用会话ID(与消息一起发送并通过管道保留)以查找 你正在等待的对象,然后它可以简单地通过Object.notify()来告诉servlet继续。

是的,这会在等待的时候在servlet容器中插入一个线程,这就是为什么新的异步内容更好,但你使用你所处理的手。您还可以向Object.wait()添加超时,如果超时,则处理时间会很长,以便您可以优雅地向客户端发出警报。

这基本上可以让你从过滤器等,以及回复队列等中解放出来。将它全部设置起来非常简单。

答案 2 :(得分:0)

实际答案应该取决于您的工人实体是外部参与方,物理位于网络外部,工作实体完成工作所需的时间等等。但是您要解决的问题是一对多通信。 .u在你的系统中添加jms协议只是因为你希望所有实体能够在jms协议中进行通信或异步是原因...前一个原因没有意义......如果是后一个原因,你可以选择其他通信协议喜欢单向的网络服务电话。 您可以使用最新的Java并发API来创建对不同工作实体的多线程异步单向Web服务调用...