我应该使用 XA 吗
常见问题解答 > JMS > 我应该使用 XA 吗
我应该使用 XA 事务(两阶段提交)吗?
JMS 的常见用法是从队列或主题中消费消息,使用数据库或 EJB 处理它们,然后确认/提交消息。
如果您使用多个资源;例如,读取 JMS 消息并写入数据库,您确实应该使用 XA - 它的目的是为多个事务性资源提供原子事务。例如,从您完成更新数据库并提交更改到您提交/确认消息的时间点之间有一个小窗口;如果在该窗口内发生网络/硬件/进程故障,则消息将重新传递,您最终可能会处理重复项。
XA 的问题在于它可能有点慢;因为 XA 协议需要多次同步到磁盘以确保它可以在所有可能的故障情况下始终正确恢复。这增加了很大的成本(在延迟、性能、资源和复杂性方面)。此外,相当多的 EJB 服务器和数据库实际上并不完全支持 XA!
小心
ActiveMQ Classic 目前不支持 XA 事务挂起/恢复语义。
XA 的替代方案
因此,一个很好的优化是使用常规的 JMS 事务 - 无需 XA - 只需在您的代码中执行一些重复消息检测以检查您是否尚未处理该消息。
例如,您可以使用来自企业集成模式的幂等消费者来解决这种情况。
或者,在伪代码中,您可以使用以下类似内容…
onMessage
try {
if I have not processed this message successfully before {
do some stuff in the database / with EJBs etc
jdbc.commit() (unless auto-commit is enabled on the JDBC)
}
jms.commit()
} catch (Exception e) {
jms.rollback()
}
这会导致更好的性能,因为您不会对 XA 协议执行许多缓慢的磁盘同步(每个事务!)。这种方法的唯一缺点是您必须使用一些特定于应用程序的逻辑来检测您是否以前处理过该消息。但是,您通常会有某种方法来检测它。例如,如果消息包含一个采购订单和版本;您是否已将该采购订单和版本存储在数据库中?
因此,只要消息具有一些 ID 和版本,您通常可以自己检测重复项,因此不需要为 XA 支付性能成本。
也可能值得阅读我应该使用事务吗。
进一步优化
执行重复检测可能会增加性能开销。例如,执行数据库查询以查看您是否以前处理过采购订单等。大多数情况下,事情都会按预期进行;只有在很少的情况下(例如,如果服务器在处理某些消息时崩溃)消息才会被重新传递。
因此,您可以使用Message.getJMSRedelivered()方法来检测消息是否已重新传递,并且只有在消息已重新传递时才执行重复检测检查。