Summary:
我有兴趣了解高吞吐量应用程序的最佳实践是什么,这些应用程序具有批量消息试图更新同一行并出现 Oracle 死锁错误的情况。我知道您无法避免这些错误,但是如何优雅地从这些错误中恢复,而不被一次又一次发生的此类死锁错误所困扰。
Details:
我们正在构建一个高吞吐量的 JMS 消息传递应用程序。生产环境将是两个 weblogic 11g 节点(每个节点运行 6 个 MDB 侦听器实例)。当我们收到大约 1000 条消息都试图更新 Oracle 数据库中的同一行时,我们遇到了 Oracle 死锁错误 (ORA-00060)。在标准 java 线程 API 中,跨节点的 Java 同步是不可能的(除非没有其他解决方案,我们不想使用任何第三方解决方案,如 terracotta 等)。
我们希望 Oracle“select for update WAIT n secs”语句会有所帮助,因为这实际上会使竞争线程(同一行)在第一个线程(首先获得该行锁的线程)完成操作之前等待几秒钟。
“SELECT FOR UPDATE WAIT n”的第一个问题是它不允许使用毫秒作为等待时间。这开始对我们的应用程序的吞吐量产生负面影响,因为放置 1 秒 WAIT(最少等待时间)会导致消息延迟。
第二件事是我们摆弄 weblogic 队列重新传递延迟参数(在我们的例子中是 30 秒)。每当一个线程因为死锁错误而反弹时,它会等待 30 秒然后重新尝试。
根据我们的经验,1000 条竞争消息在很多情况下都需要很长时间才能得到处理,因为死锁不断发生。
我知道,在当前的架构中,无论如何我们都应该会遇到死锁错误(在 1000 个竞争消息的情况下),但应用程序应该具有足够的弹性,能够在重试循环消息后从这些错误中恢复。
知道我们在这里缺少什么吗?以前处理过类似问题的人吗?
我正在寻找一些设计思想,可以使这项工作具有弹性,以便它从这种死锁情况中恢复,并最终在合理的时间内处理所有消息,而无需使用太多额外的硬件。
计算细节:这 1000 条消息将分别创建 4 个不同位置类型的 4 个对象,每个对象都有一个与其关联的数量。这些数量必须合并到这 4 个不同的槽位中(取决于仓位类型)。当每个单独的线程更新这 4 个单独的槽时,就会发生死锁。在应用于数据库行之前,我们已经按特定顺序对这些单独的更新进行了排序,以避免任何可能的竞争条件。