2016-06-08 64 views
19

假设我们有一个参与XA事务的数据库(例如Oracle)和JMS提供者(例如HornetQ)。一条消息被发送到一个JMS队列,并且一些数据在同一个分布式事务中被保存在数据库中。事务提交后,消息使用者将读取持久数据并在单独的事务中处理它们。XA事务中的数据一致性

关于第一XA事务,下面的事件序列可以由事务管理器(如,JBoss)

  1. 制备(HornetQ的)
  2. 制备(Oracle)的
  3. 提交(HornetQ的)执行的
  4. 提交(甲骨文)

如果消息消费者开始读取数据提交后会发生什么在HornetQ完成,但仍在Oracle中执行?消息使用者是否会读取陈旧的数据?

这个问题可以推广到任何种类的参与XA事务的多种资源,也就是说,在另一个并发事务的读者可以获得不一致状态的小时间窗口(执行提交阶段时) (通过读取来自一个资源的提交数据和来自另一个资源的陈旧数据)?

我想说,事务性资源阻止这种情况的唯一方法是在准备阶段完成之前阻止受影响数据的所有读者,直到发出提交。这样上面提到的示例消息使用者将阻塞,直到数据在数据库中提交。

+0

这是一个很好的问题,这是JTA IMO的主要问题,即使规范太过轻描述(因为它应该)这样一个复杂的机制,它也没有适当的记录。 –

+0

此外,这不是更糟糕的用例,请考虑当XAResource实现者无法恢复时您提交失败的情况。 –

+1

详细规范太久无法回答,但可以在Oracle白皮书中找到[“XA和Oracle受控分布式交易”](http://www.oracle.com/technetwork/products/clustering/overview/distributed -transactions-and-xa-163941.pdf)的第12页“分布式事务和数据库锁定”一章。 – ThinkJet

回答

4

不幸的是,XA事务不支持一致性。映射到CAP theorem XA跨多个数据存储解决可用性和分区容忍问题。这样做必须牺牲一致性。使用XA时,您必须拥抱最终的一致性。

在任何情况下,创建CP或AP的系统都是hard enough,无论您的数据存储或事务模型如何,都将面临此问题。

1

我有一些基于Weblogic JMS和Oracle 11g的不同环境的经验。在这个答案中,我猜想它正在工作正好与一样。我希望我的回答会帮助你。

在我们的案例中,有一个“遥远的”系统,它必须根据本地系统内发生的不同事件进行通知。另一个系统也会进入我们的数据库,所以用例似乎与您的问题几乎完全相同。事件的顺序与你的完全一样。在测试系统上,没有一个单一的faulire。每个人都认为它会起作用,但我们中的一些人怀疑它是否是正确的解决方案。随着软件的生产,一些BPM流程运行不可预测。所以一个简单的回答你的问题:是的,这是可能的和每个人都应该知道它。

我们的解决方案(在我看来)是不是一个很好的计划,但我们认识到两者之间的小时间窗口提交时,制动系统,所以我们增加了一些“延迟”队列(如果我记得它像1-2分钟)。完成其他提交并读取一致的数据就足够了。在我看来,这不是最好的解决方案。它不解决syncronisation问题(如果oracle事务超过1-2分钟?)。

Here是一篇很棒的博客文章,值得一看,最后的解决方案对我来说似乎是最好的。我们在另一个系统中实现了它,它的工作方式更好。 重要的是要注意,您应该限制重试(重新读取)以防止“卡住”线程。(有一些错误报告。)有了这个限制,我目前无法找到更好的解决方案,所以如果有人有更好的选择,我期待听到它。:)

编辑:打字。

+0

“如果oracle事务超过1-2分钟,该怎么办”那么我们所谈论的延迟就是提交事务并不是整个事务的持续时间,最多几十毫秒。此外,JMS消息通常通过网络发送,这应该比第二阶段提交花费更长的时间。根据我的说法,你的设计还有另一个问题。 – Gab

+0

通过获取对从消息使用者读取的数据的锁定(例如“select for update”),比通过超时更容易解决这个问题吗?如果超时,我们可以为每条消息引入过大的固定延迟,或者如果超时过低,则会增加再次读取陈旧数据的风险。 –

+0

简单的锁定并不是我所看到的一步。在读取时将不会显示所需的数据(插入不是承诺喷气机)。我提到的手动同步(在我看来)是一种快速可靠的解决方案。如果需要,我会在2天内从假期回来,我可以绘制流程图。在手机上,我的可能性相当有限。 – Mark

0

是的。即使事务失败并在事后回滚,外部系统也可能接收并使用您实际提交的之前发送的消息

在过去的两年中,我一直在使用WebSphere MQ作为JMS提供程序和Oracle 11g作为后台数据库的XA事务来维护和开发分布式系统。
其中一个批处理作业将从DB读取脱机消息,将它们发送给JMS并将它们标记为在DB中发送 - 这些都是作为相同XA事务的一部分。如果任何消息或数据库失败,交易将被回滚。

有些时候,对于JMS来说消息太大,导致send()失败,整个事务回滚(),导致数据库不变。
但是,外部消费者仍然在接收和处理回滚之前发送的每条消息。我知道,因为他们会为我处理的每封邮件发送一封电子邮件,并且我收到了大量关于未在数据库中标记为已发送的邮件的电子邮件(因为事务已回滚)。

如果这个外部系统是以某种方式SELECT COUNT(*)我的系统发送的消息数量,它将读取0个消息发送,尽管已经消耗了数百个消息。

因此,即使在使用XA事务时,外部系统也可能读取陈旧的数据。

0

我会插入一个状态字段,所以在每一步之后,如果它成功了,状态将被更新,读者应该在执行操作之前检查状态。