1

我有一个独立的 Java 进程,它从 JMS 持久主题中读取消息并将它们提交到线程池进行处理。出于明显的并发原因,我这样做是为了保持这些消息的处理顺序,我仍然将它们提交到单个线程池。现在这是我对 JVM 崩溃的担忧。

--Non Transactional
我没有在 Transactional 上下文中阅读和处理每条消息,我避免这样做,因为它减慢了我的进程。所以,我在线程池的阻塞队列中累积消息。但是,如果 JVM 在线程池中有 10 条消息等待处理时崩溃,我将丢失该数据。

--事务
我相信如果我阅读并处理事务中的每条消息,如果出现问题,该消息将在备份时重新传递给进程。

由于这是许多在低延迟系统中工作的人的常见问题,想知道有经验的人如何解决这个问题?谢谢。

4

1 回答 1

2

彼得的 AFAIK 是正确的。解决此问题的一种方法是,如果该模式适用于您,则使用某种分界线来创建不同的队列以将消息分组到其中。也就是说,这个要求经常分解为“一个帐户的所有消息必须按顺序处理”之类的意思。所以如果你有类似的东西,你可以创建:

  • 一个主题和多个订阅者,每个订阅者都使用专有选择器(或子主题模式)
  • 多个主题,每个主题都有一个订阅者。

然后您的发布商必须确定:

  • 已发布消息上的标头,以便为订阅者影响更正选择器,或
  • 要发布的正确子主题,或
  • 发布的正确主题

一种易于维护的模式是使用您的一个业务字段(例如,帐号)并在其上计算mod(x),其中x是您希望分担工作负载的订阅者数量。希望您的业务密钥是数字的,并且会给您一个不错的分布,但您始终可以使用其他一些确定性算法通过反转密钥和/或散列它们的非数字值来生成此数字。

顺便说一句,您的大纲更像是点对点/JMS 队列,而不是 Pub-Sub/JMS 主题。您确定要使用主题吗?

如果您绝对不能丢失数据,那么您应该使用事务性消息。如果您使用事务性消息,则不能委托给线程池。JMS 消息的事务上下文(即会话)绑定到接收消息的线程,因此除非您启用一些“有趣的业务”来将此上下文传输到另一个线程.....

我什至不知道如何完成那句话。

==== 更新 ====

现在我想一想,如果您可以从并行处理消息中受益,您可以在一个事务中检索一批消息,并将它们全部委托给ExecutorService.invokeAll调用,等待完成并在它们完成时提交事务'都完成了。如果 invokeAll 超时,或者其中一个任务引发异常,那么您将不得不回滚事务或采取某种补偿措施。

于 2013-02-04T19:55:16.630 回答