在事务提交之前传递 JMS 消息
Posted
技术标签:
【中文标题】在事务提交之前传递 JMS 消息【英文标题】:Delivery of JMS message before the transaction is committed 【发布时间】:2011-01-25 23:21:37 【问题描述】:我有一个非常简单的场景,涉及应用服务器 (Glassfish) 中的 数据库 和 JMS。场景非常简单:
1. an EJB inserts a row in the database and sends a message.
2. when the message is delivered with an MDB, the row is read and updated.
问题是有时消息在插入提交之前传递到数据库中。如果我们考虑 2 阶段提交协议,这实际上是可以理解的:
1. prepare JMS
2. prepare database
3. commit JMS
4. ( tiny little gap where message can be delivered before insert has been committed)
5. commit database
我已经讨论过这个问题with others,但答案总是:“奇怪,它应该开箱即用”。
那么我的问题是:
如何开箱即用? 我的场景听起来很简单,为什么没有更多人遇到类似问题? 我做错了吗?有没有办法正确解决这个问题?以下是关于我对问题的理解的更多细节:
仅当参与者按此顺序处理时,才会存在此时间问题。如果 2PC 以相反的顺序处理参与者(首先是数据库,然后是消息代理),那应该没问题。这个问题是随机发生的,但完全可以重现。
在 Glassfish 文档中,我发现无法控制 JTA、JCA 和 JPA 规范中分布式事务参与者的顺序。我们可以假设它们会在使用时按照顺序被登记到分布式事务中,但是使用 JPA 等 ORM 时,很难知道何时刷新数据以及何时真正使用数据库连接。有什么想法吗?
【问题讨论】:
问题:MDB 是否在同一台服务器上运行?如果是,MDB 是否也使用 JPA 来更新记录?如果是,您是否使用二级缓存(我在另一篇文章中读到您正在使用 Hibernate)?最后,如果是(使用缓存),我可以知道您使用的是什么缓存实现吗? @Elister。一切都在同一台服务器上运行。我们到处使用 JPA。二级缓存完全被禁用。 (我们发现的解决方法是使用原生查询select * for update
来读取 MDB 中的行。然后它会等到第一个事务被提交。)
你能显示一些伪代码吗?如果您使用不同的 EJB,等等
@Pascal 我创建了一个重现测试用例。这是源代码和说明:forums.java.net/jive/message.jspa?messageID=353154#391321
WebSphere 7 已添加此支持。查看“事务资源的提交优先级”部分publib.boulder.ibm.com/infocenter/wasinfo/fep/index.jsp?topic=/…
【参考方案1】:
您正在体验经典的 XA 2-PC 竞态条件。它确实发生在生产环境中。
我想到了 3 件事。
-
最后一个代理优化,其中 JDBC 是非 XA 资源。(丢失恢复语义)
具有 JMS 交付时间。 (故意丢失实时)
在 JDBC 代码中构建重试。 (对功能影响最小)
Weblogic 的 LLR 优化避免了这个问题,并为您提供所有 XA 保证。
【讨论】:
+1 感谢您的回答。所以没有办法在不依赖应用程序的情况下简单地实现它。服务器高级优化? (规范没有强制应用服务器有时间交付最后的代理优化。) 顺便说一句,我在 glassfish 论坛上有效地了解了最后一次代理优化。不过,我不知道高级 LLR 变体。关于重试逻辑,我们实际上已经绕过select * for update
的问题,简单得多。我很高兴听到这是一个“经典”问题。不过,我没有得到的是规范本身并没有解决这个问题,例如要求我们可以为参与者指定首选顺序。
@ewernli 我现在面临同样的问题。你最后是怎么解决的? select * for update
w.r.t 是什么意思?重试?
@Theo select * for update
将为读取的行获取锁。插入行的第一个 tx 对该行有一个锁,直到 tx 被提交。我们在消息中传递已插入(但尚未提交)的行的 id,如果在提交插入之前实际触发了 MDB,则使用 select * where id='id of the row inserted' for update
将暂停第二个 tx,直到提交第一个 tx 中的行并且可以获取锁。
顺便说一句,这也发生在 MSDTC 中——我们在涉及 MSMQ 和 MSSQL 的分布式事务中经历过。我能找到的最接近的参考资料(来自“MS 世界”)是来自 Ayende Rahien 的 this 文章。我在通常的 MS 论坛上找不到任何报告,在 MSDN 文档中也找不到任何关于此的警告。不用说,我也找不到任何方法告诉 MSDTC 确保一定的操作顺序。我们通过重试解决了这个问题,直到我们可以看到保存到数据库的更改。以上是关于在事务提交之前传递 JMS 消息的主要内容,如果未能解决你的问题,请参考以下文章