JMS 队列上多线程消息处理的最佳实践

Posted

技术标签:

【中文标题】JMS 队列上多线程消息处理的最佳实践【英文标题】:Best practice for multi-threaded message processing on JMS queues 【发布时间】:2012-12-05 21:24:29 【问题描述】:

我目前正在将 JMS 支持添加到类似应用程序服务器的框架中。 JMS 将由 HornetQ(独立代理,服务器类路径上的 hornetq jars)实现,但既没有 JBoss,也没有 spring,也没有其他任何可以提供 MDB 的东西。

下一步是将消息侦听器添加到允许并行处理传入消息的 xa 队列。有些消息会启动长时间运行的任务,因此基本思想是从 onMessage 方法生成工作线程。

在我漫长的互联网之旅中,我遇到了this discussion,其中一位参与者提到,他不会这样做,而是使用额外的内部队列来完成任务:(单线程)消息侦听器会简单地抓取来自入站队列的消息并为内部队列创建新消息,在该内部队列的另一端,一些工作线程争夺传入消息。一旦入站消息被“复制”到内部队列(这对我来说没问题),就会得到确认。

不幸的是,他们没有说为什么最好不要从onMessage 方法产生工作线程 - 也许是因为如果池中的所有线程都忙,侦听器会阻塞。所以我正在寻找设计决策的利弊:

从消息监听器的 onMessage 方法启动工作线程 使用内部队列“向工作线程发送消息”

【问题讨论】:

【参考方案1】:

撇开事务限制不谈,是否让多个线程(或进程)从队列中读取数据归结为消息顺序是否重要。显然,如果顺序很重要,那么单个线程自然会维护该顺序,而多个线程将不提供这样的保证。

您通常会发现,顺序很重要,但只是所有消息的一个子集。在这种情况下,如果单个线程不高效,您需要将这些消息从队列中取出并在尽可能短的时间内重新排队,因为为了保持顺序,您必须使用从初始值读取的单个线程queue - 因此使用一个或多个内部队列。这导致的问题是事务将在消息完全处理之前关闭,因此您需要某种临时存储来确保如果在处理发生之前进程发生故障,消息不会被丢弃。

如果正如您的问题所暗示的那样,您不太担心丢弃消息,那么 java.util.concurrent.BlockingQueue 听起来就像您需要的内部队列,每个队列都有一个线程服务。

【讨论】:

以上是关于JMS 队列上多线程消息处理的最佳实践的主要内容,如果未能解决你的问题,请参考以下文章

JMS 生产者最佳实践 [关闭]

消息队列最佳实践消息恰好被消费一次

将数据库与消息队列解耦的最佳实践

RabbitMQ实战:消息通信模式和最佳实践

消息队列实现复制的最佳实践

RocketMQ消息队列的最佳实践