我曾经在一个相当大的规模上对集群中的消息进行了顺序处理——每天处理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来使时钟保持合理同步。