在OC4J集群中确保JMS消息的串行处理

4
我们有一个应用程序,使用消息驱动的bean来处理JMS消息。该应用程序部署在OC4J应用服务器上。(10.1.3)
我们计划将此应用程序部署在多个OC4J应用服务器上,并配置为运行在集群中。
问题出现在此集群中的JMS消息处理中。我们必须确保,在任何时候,在整个OC4J集群中只处理一个消息。这是必需的,因为消息必须按照时间顺序处理。
您知道是否有配置参数可以控制OC4J集群中的消息处理吗?
或者您认为我们必须实现自己的同步代码,以在集群中同步消息驱动的bean?

大家好,感谢您们对设计方面的见解。我向您保证,设计是可以的。该应用程序的主要目标不是处理jms消息,队列仅用于处理可以在后台完成且不需要高性能的任务。这些消息的要求是必须按照放置的顺序进行处理,并且不能并行处理,否则将发生olc错误。问题是,在集群上运行的j2ee应用程序中是否有一种简单的方法来配置只有一个活动mdb? - Ladislav Petrus
当然可以使用我描述的单个租约机制。这非常简单,尤其是如果已经有一个数据库存在的话。 - Don Branson
那么,您需要多少吞吐量呢?例如,每秒钟有多少条消息? - Don Branson
我们认为开发自定义同步解决方案是最后的选择。在这种情况下,据我们所知,我们将不得不放弃MDBs的概念,并且我们将不得不开发自己的消息处理架构,以使我们能够在集群实例之间进行同步。 - Ladislav Petrus
我已经更新了我的答案以回应上面的评论。 - Don Branson
显示剩余2条评论
3个回答

5
我曾经在一个相当大的规模上对集群中的消息进行了顺序处理——每天处理150万条以上的消息,使用了竞争消费者模式和租约模式的组合。
然而,你只能同时处理一次 trans 的要求将阻止你实现目标。我们有同样的基本要求——必须按顺序处理消息。至少我们是这么认为的。然后我们有了一个领悟——随着我们更深入地思考这个问题,我们意识到我们并不需要完全有序。实际上,我们只需要在每个账户内进行排序。因此,我们可以通过将不同服务器集群中的帐户范围分配给不同的服务器来分散负载。然后,每个服务器负责按顺序处理给定帐户的消息。
这里还有第二个巧妙的部分——我们使用了租约模式来动态地将帐户范围分配给集群中的各个服务器。如果集群中的一个服务器关闭,另一个服务器将获取租约并接管第一个服务器的职责。
这对我们起作用了,并且该过程在生产中运行了大约4年,直到由于公司合并而被替换。
编辑:
我在这里更详细地解释了这个解决方案:http://coders-log.blogspot.com/2008/12/favorite-projects-series-installment-2.html 编辑:
好的,我明白了。你已经在需要的级别上进行处理,但由于要部署到集群中,你需要确保只有一个 MDB 实例正在主动从队列中拉取消息。此外,你需要最简单可行的解决方案。
我认为你不需要放弃现有的 MDB 机制。我们实际上是在谈论分布式锁机制的要求,不要太花哨。
所以,让我建议这个。当你的 MDB 注册接收来自队列的消息时,它应该检查分布式锁,并查看是否可以获取它。第一个获取锁的 MDB 获胜,只有它将注册接收消息。因此,你现在拥有了序列化。这个锁应该采取什么形式?有很多可能性。那么,这个怎么样?如果你有访问数据库的权限,它的事务锁已经提供了一些你需要的东西。创建一个带有单个行的表。行中包含当前持有锁的服务器的标识符和过期时间。这是服务器的租约。每个服务器都需要有一种生成其唯一标识符的方法,例如服务器名称加线程 ID。
如果服务器可以获得行的更新访问权限,并且租约已过期,则应抓取该行。否则,它会放弃。如果它获取了租约,则需要在不久的将来(例如五分钟左右)更新该行,并提交更新。活动服务器应在其到期之前更新租约。我建议在剩余时间的一半时进行更新,因此,如果租约在五个以上到期,则每2.5分钟进行一次更新。通过这样做,现在您已经实现了故障转移。如果主要MDB崩溃,另一个MDB(仅一个)将接管。
我认为这应该很简单。现在,您希望休眠的MDB定期检查锁是否释放。
因此,活动MDB和休眠MDB都必须定期执行某些操作。您可以使它们生成一个单独的线程来执行此操作。许多应用程序引擎供应商可能对此不满意,但添加一个线程并不是什么大问题,特别是因为它大部分时间都在睡眠。另一个选择是连接许多引擎提供的计时器机制,并定期唤醒您的MDB以检查租约。
哦,顺便说一下-请确保服务器管理员采用NTP来使时钟保持合理同步。

谢谢你的提示!当我阅读你的回复时,我想起我们完全忘记了MDB生命周期方法。我认为我们将能够提出一个简单的机制,仅依赖于这些方法来确保集群中只有一个MDB正在处理消息。我们将使用Oracle数据库提供的锁定机制(dbms_lock)。当我们有一个可行的解决方案时,我会发布详细信息。 - Ladislav Petrus

-1
第一点:这是一个相当糟糕的设计,只能一次处理一个消息,会严重限制性能。我假设你只是为了容错而进行集群,因为你不会得到性能提升?
你是使用OC4J的默认JMS实现还是其他实现?
我以前用过IBM的MQ,它有一个特性,可以将队列标记为独占,这意味着只有一个客户端可以连接它。这似乎提供了你想要的功能。
另一种选择是引入一个序列ID(简单地增加计数器),并且处理消息的客户端将检查序列ID是否是下一个预期值,如果不是,则将消息放回。这种方法需要不同的客户端在某个中央共享数据存储中持久化他们看到的最后一个有效序列ID,例如数据库。

我们正在使用Oracle高级队列作为后端。 - Ladislav Petrus

-1

我同意stevendick的观点:也许你在设计上偏离了轨道。关于序列ID或类似方法,我建议你深入了解消息架构,可以参考Gregor Hohpe和Bobby Woolf所著的《企业集成模式:设计、构建和部署消息传递解决方案》。这是一本非常好的书,包含了许多有用的模式...我相信你面临的问题和挑战在书中都有很好的描述。


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