Sql-Server

SQL Server、MSDTC 和 WebSphere 的 XA 事務超時

  • January 27, 2016

我有一個使用 SQL Server 2008 實例執行 XA 事務的 Java/WebSphere 應用程序。在某些環境中,一切都按預期工作。在我們的兩個環境中,事務會間歇性地失敗。

關於環境的一些資訊:

  • 應用程序伺服器是執行 WebSphere 8.5.5.3 的 Linux VM。它使用的是 4.0 版的 SQL Server JDBC 驅動程序。為 XA 配置數據源。
  • 數據庫伺服器是執行 SQL Server 2008 的 Windows VM
  • 事情是否有效似乎取決於數據庫伺服器上的數據庫。在損壞的環境中,我可以將應用程序伺服器配置為使用損壞的環境中的數據庫,並且事情不再起作用。反之亦然——如果我將損壞環境中的應用程序伺服器配置為在工作環境中使用數據庫伺服器,那麼應用程序將正常工作。

在應用程序伺服器上,當事務失敗時,我會看到這樣的堆棧跟踪:

com.microsoft.sqlserver.jdbc.SQLServerException: Distributed transaction completed. Either enlist this session in a new transaction or the NULL transaction.
   at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDatabaseError(SQLServerException.java:216)
   at com.microsoft.sqlserver.jdbc.SQLServerStatement.getNextResult(SQLServerStatement.java:1515)
   at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.doExecutePreparedStatement(SQLServerPreparedStatement.java:404)
   at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement$PrepStmtExecCmd.doExecute(SQLServerPreparedStatement.java:350)
   at com.microsoft.sqlserver.jdbc.TDSCommand.execute(IOBuffer.java:5696)
   at com.microsoft.sqlserver.jdbc.SQLServerConnection.executeCommand(SQLServerConnection.java:1715)
   at com.microsoft.sqlserver.jdbc.SQLServerStatement.executeCommand(SQLServerStatement.java:180)
   at com.microsoft.sqlserver.jdbc.SQLServerStatement.executeStatement(SQLServerStatement.java:155)
   at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.executeUpdate(SQLServerPreparedStatement.java:314)
   at com.ibm.ws.rsadapter.jdbc.WSJdbcPreparedStatement.pmiExecuteUpdate(WSJdbcPreparedStatement.java:1187)
   at com.ibm.ws.rsadapter.jdbc.WSJdbcPreparedStatement.executeUpdate(WSJdbcPreparedStatement.java:804)
   at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:186)

當我查看數據庫伺服器上 MSDTC 的日誌時,我看到:

time=12/22/2015-10:47:48.611    eventid=RM_ENLISTED_IN_TRANSACTION                  tx_guid=690a94a2-a060-4eb9-8966-ef25b0fa001b        resource manager #1001 enlisted as transaction enlistment #1. RM guid = '280f3497-9cc1-4689-b612-7a08cce82e2b'
time=12/22/2015-10:47:57.612    eventid=ABORT_DUE_TO_TRANSACTION_TIMER_EXPIRED      tx_guid=690a94a2-a060-4eb9-8966-ef25b0fa001b        transaction timeout expired
time=12/22/2015-10:47:57.612    eventid=TRANSACTION_ABORTING                        tx_guid=690a94a2-a060-4eb9-8966-ef25b0fa001b        transaction is aborting
time=12/22/2015-10:47:57.612    eventid=RM_ISSUED_ABORT                             tx_guid=690a94a2-a060-4eb9-8966-ef25b0fa001b        abort request issued to resource manager #1001 for transaction enlistment #1
time=12/22/2015-10:47:57.612    eventid=RM_ACKNOWLEDGED_ABORT                       tx_guid=690a94a2-a060-4eb9-8966-ef25b0fa001b        received acknowledgement of abort request from the resource manager #1001 for transaction enlistment #1
time=12/22/2015-10:47:57.612    eventid=TRANSACTION_ABORTED                         tx_guid=690a94a2-a060-4eb9-8966-ef25b0fa001b        transaction has been aborted

我一直看到 ABORT_DUE_TO_TRANSACTION_TIMER_EXPIRED 事件在 RM_ENLISTED_IN_TRANSACTION 事件發生 9 秒後發生。問題是數據庫伺服器上的 MSDTC 事務超時配置為 60 秒。我已嘗試更改此超時,但它根本不會影響行為。我在 WebSphere 中也看不到任何與 9 秒間隔匹配的事務超時設置。這個超時來自哪裡,我該如何改變它?

我們發現了我們的問題。我們有另一個使用 Atomikos 進行 JTA 事務的非 WebSphere 應用程序。Atomikos 預設為其事務設置 10 秒超時,除非您設置 com.atomikos.icatch.default_jta_timeout 屬性。Atomikos 在參與事務的所有 XAResource 實例上設置此超時。由於某種原因,這導致 10 秒超時被全域應用於使用該 MSDTC 實例的所有事務。還值得注意的是,WebSphere 的事務管理器不會在參與的 XAResource 實例上呼叫 setTimeout,這可能是另一個應用程序影響這些事務的部分原因。重新啟動 MSDTC 似乎可以清除全域超時,直到 Atomikos 事務再次執行。

可能值得注意的是,其他 JTA 事務管理器(如 Bitronix)在使用 XA 訪問 SQL Server 時可能會遇到相同的問題。此問題也可能特定於 SQL Server JDBC Driver 4.0 版,並且可能會在以後的版本中得到修復。但是,我無法測試這些陳述。

如果您碰巧遇到同樣的問題,您應該能夠使用以下步驟進行驗證:

  1. 重啟 MSDTC
  2. 在您的 WebSphere 應用程序中執行事務。他們不應該因為超時而失敗。嘗試多次交易 - 足以讓事情順利進行。
  3. 使用您的 Atomikos 應用程序執行事務。
  4. 再次使用 WebSphere 執行事務。如果事務超過 10 秒,它現在應該失敗並被 MSDTC 中止。
  5. 重啟 MSDTC
  6. 再次使用 WebSphere 執行事務。即使超過 10 秒,它也不會再出現超時錯誤。

引用自:https://serverfault.com/questions/748319