JMS消息排序和事务回滚

时间:2015-09-02 11:47:55

标签: java jms ibm-mq

我们正在建立一个系统,它将通过JMS从一个应用程序向另一个应用程序发送消息(如果重要的话,使用Websphere MQ)。这些消息的形式为"创建x"或"删除x"。 (最终结果是需要通知第三方系统创建和删除消息,因此JMS队列的读取端将与第三方系统通信,而JMS的写入结束队列只是广播要处理的消息)

我们在这里担心的问题是其中一条消息是否失败。这里最初的想法只是将故障回滚到JMS队列上,让普通的重试机制处理它。这种方法一直有效,直到你得到一个删除后跟一个相同标识符的Create,例如

  • 删除123 - 失败,回滚到队列
  • 创建123 - 成功
  • 删除123 - 从早期故障重试

最终结果是第三方被告知创建123,然后立即被删除123,而不是相反。

虽然不理想,但从我所阅读的内容来看,Message Affinity似乎对此有所帮助,因此我们可以保证以正确的顺序处理消息。但是,我不确定在处理消息并将消息重新发送到队列时消息关联性如何工作? (消息亲和力通常被认为是一个坏主意,但这里的负载不会很大,而且有害信息的风险非常低。这只是我们和#的第三方的风险。 39;重新互动有一个我们关注的短暂中断)

如果做不到,有没有更好的想法如何做到这一点?

编辑 - 进一步的复杂化。我们与第三方集成的系统是直到最近才更换他们使用的系统。因此,已经存在于第三方的一堆数据,但实际上很难实现这一点。 (第三方甚至不会发回成功/失败消息,只是确认收到!),所以我们实际上并不知道系统的初始状态。

2 个答案:

答案 0 :(得分:2)

解决此问题的最终方法是在消息中包含一个序列,以便较早的消息不能覆盖后一个消息。

曾几何时,您在银行的交易按其到达的顺序处理。然而,正是这个确切的问题导致了这种变化。人们意识到他们的帐户余额可能会受到正面或负面影响,具体取决于交易的处理顺序。当它被遗忘时,它偶尔会成为人们的问题,但总的来说没有人感到恶意。

后来,银行开始在白天备忘录交易,然后在处理之前将它们分类为对银行最有利的订单。例如,如果最大的支票首先清算且账户资金不足,则几个较小的支票可能会反弹,从而为银行产生多次反弹费用。一旦发现这已经成为普遍的做法,它就被改为始终以最有利于账户持有人的顺序应用交易。 (至少在美国这里。)

这是一个常见的问题,它已经多次解决,第一次是几十年前。

的企业级应用程序确实没有任何借口
  1. 使用异步消息传递,其中无法保证按设计的交付顺序,
  2. 包含对交货单的固有依赖性,以确保交易和数据的完整性。
  3. 当提到作为运输问题时,提及消息亲和力暗示了对此的解决方案。要保证邮件订单的发送,需要以下内容:

    • 消息的唯一发件人
    • 发送邮件的唯一一个节点。
    • 消息的发件人和收件人之间唯一的一条路径。
    • 收到邮件的唯一一个队列。
    • 在同步点下处理的所有邮件。
    • 在存在孤立事务时挂起处理任何消息的能力(连接异常处理)。
    • 输入队列上没有回退队列。
    • 如果消息遍历某个频道,则无DLQ。
    • 不在路径上的任何队列中使用优先传递。
    • 一个且只有一个消息接收者。
    • 除了通过向托管QMgr的节点添加CPU和内存之外,无法扩展应用程序。

    或者可以使用备忘录发布,补偿交易或通常用于消除序列依赖性的任何其他技术在应用程序设计中解决问题。

    (旁注:如果有问题的应用程序是一个现成的供应商软件包,那么在我看来,这会产生一个可信度问题。如果一个如此普通的东西退出,那么任何应用程序都无法声称它是强大的消息可能会破坏数据的完整性。)

答案 1 :(得分:1)

避免上述情况的一种方法是对邮件失败进行不同分类;请记住,您的邮件应按顺序处理。(邮件亲和力)

  

考虑情景: -

     

如果应用程序收到之前未收到Create x的Delete X,         然后将此错误方案归类为“Business Error”,因为此错误发生,因为         Message的制作者发错了消息。或者我们可以说错误的顺序发送消息的生产者。

将此错误归类为“Business Error”后,您不应该调用回滚;而不是将此消息插入到数据库中,并将“业务错误”作为标识。

因此,通过这种方式,您可以从队列中提交此消息并降低回滚风险,并进一步降低应用程序行为不一致的风险。

  

现在考虑另一个场景: -

     

如果您的应用程序本身存在某些问题(例如,数据库或Web服务器出现故障或任何此类技术错误),那么在这种情况下使用JMS队列的回滚机制并将此错误视为“Technical Error”。 / p>

因此,如果发生任何“Technical Error”,JMS队列将重试消息,直到您的应用程序能够接受并处理它们。

一旦您的应用程序在此“Technical Error”之后启动并尝试按顺序处理消息,此处应用相同的规则,即如果发生“业务错误”,则该消息将不再重试。

  

注意:“业务错误”分类应得到所有各方的同意,即如果您将任何消息标记为“Business Error”,则表示此消息不再有用,您的制作人应该为任何有效的'创建x'发送新的“删除x”。

您可以考虑的一些“业务错误”是 -

  1. 在“创建x”

  2. 之前收到“删除x”
  3. 在“创建x”

  4. 之后收到“创建x”
  5. 在有效“删除x”

  6. 后收到“删除x”