[譯] Spring 的分散式事務實現-使用和不使用XA — 第三部分

掘金翻譯計劃發表於2019-04-11

其它建議

示例中的 ChainedTransactionManager 具有簡單的優點:它不用為可用的擴充套件和優化費心。另一種方法是在第二個資源加入時,使用 Spring 中的 TransactionSychronization API 為當前事務註冊一個回撥。這是 best-jms-db 示例中的方法,其中關鍵特性是 TransactionAwareConnectionFactoryDataSourceTransactionManager 的組合。這種特殊情況可以擴充套件泛化到使用 TransactionSynchronizationManager 的非 JMS 資源上。優點是,原則上只有加入該事務的那些資源將被登記,而不是鏈中的所有資源。然而,配置仍然需要知道潛在事務中的參與者對應於哪些資源。

此外,Spring 工程團隊正在為 Spring Core 考慮開發「Best Efforts 1PC 事務管理器」功能。如果你喜歡該模式,並且希望在 Spring 中看到對它的明確和更透明的支援,你可以在這個 JIRA 問題中投票。

非事務訪問模式

非事務訪問模式在某種特殊的業務流程中才有意義。這裡是指,有時你需要訪問的資源是邊緣的,不需要在事務中。例如,你可能需要向審計表中插入一行,該行與業務事務是否成功無關,它只是記錄了嘗試做某事。更常見的是,人們高估了他們需要對一個資源進行讀寫更改的程度,往往只讀訪問就足夠了。或者寫操作可以被在更細粒度上加以控制,使得在寫操作中出現錯誤時,錯誤可以被考慮或忽略。

在這些情況下,保持在事務之外的資源可能實際上具有它自己的事務,但是它不與正在發生的任何事務同步。如果你使用 Spring,則主要事務由 PlatformTransactionManager 驅動,邊緣資源可能是從不由事務管理器控制的資料庫「連線」從「資料來源」獲取。所有這一切都發生在每個訪問邊緣資源的預設設定是 autoCommit = true 時。讀操作不會看到在另一個未提交的事務中同時發生的更新(假設有合理的預設隔離級別),但是寫操作的效果通常會被其他參與者立即看到。

這種模式需要更仔細的分析和更多設計業務流程的信心,但它不是完全不同於 Best Efforts 1PC。當出現任何問題,提供補償事務的通用服務對於大多數專案來說是不現實的。但是簡單的使用情況涉及冪等的、只執行一個寫操作(可能多次讀)的服務並不罕見。這些是非事務性情境的理想情況。

飛行之翼:反模式

最後一個模式是一個反模式。它往往出現在開發人員不瞭解分散式事務或不知道他們已經實現了一個分散式事務的情況下。如果沒有顯式呼叫底層資源的事務 API,你不能只是假設所有的資源都加入一個事務。如果你使用除 JtaTransactionManager 之外的 Spring 事務管理器,就會有一個事務資源依附到這個模式。該事務管理器將用於使用 Spring 宣告性事務管理功能(如 @Transactional)來攔截方法執行。不能期望在同一事務中登記其他資源。通常的結果是正常情況下一切沒有問題,但只要有一個異常,使用者會發現其中一個資源沒有回滾。導致此問題的典型錯誤是使用 DataSourceTransactionManager 和使用 Hibernate 來實現倉庫。

該使用哪個模式呢?

我將通過分析這些模式的利弊得出結論,幫助你瞭解如何在它們之間做出決定。第一步是確認你有一個需要分散式事務的系統。一個必要的(但不是充分的)條件是存在具有多於一個事務資源的單個程式;一個充分的條件是這些資源在單個用例中一起使用,通常由對你的架構中的服務級別的呼叫驅動。

如果你還沒有分辨出分散式事務,你可能已經實現了飛行之翼模式。遲早你會看到應該已回滾但並沒有回滾的資料。可能在真實的錯誤發生很久後你才能看到所造成的影響,這時已經很難追溯回失敗的源頭。開發人員可能會不小心使用飛行之翼模式,因為他們認為 XA 已經在發揮作用,但實際上沒有配置基礎資源來參與事務。我曾經在一個專案上工作,其中資料庫已被另一個組安裝,並且在安裝過程中關閉了 XA 支援。系統執行了好幾個月,然後奇怪的錯誤開始滲透到業務流程中。診斷這個問題花了很長時間。

如果你的混合資源用例很簡單,可以負擔得起分析和重構,那麼非事務資源模式可能是一種選項。當其中一個資源主要是讀取,寫入操作可以通過對重複項的檢查來保護時,這種模式最有效。即使在失敗之後,非事務性資源中的資料也必須在業務中有意義。稽核、版本控制和日誌記錄資訊通常適用於此類別。在這個模式中,失敗將是相對常見的(任何時候都有可能發生事務回滾),但你可以相信這個沒有副作用。

Best Efforts 1PC 適用於要求失敗率低,且不希望有像 2PC 那麼大的開銷的系統。選擇這個模式帶來的效能提升是很顯著的。它的設定比非事務性資源更為棘手,但它不需要那麼多的分析,並且用於更通用的資料型別。絕對的資料一致性要求業務處理對「外部」資源(除第一次以外的任一次提交)都是冪等的。訊息驅動的資料庫更新是一個完美的例子,Spring 對它已經有相當好的支援。更不常見的情況需要一些額外的框架程式碼(這些框架程式碼可能最終會是 Spring 的一部分)。

共享資源模式非常適用於特殊情況,通常涉及兩個特定型別和平臺的資源(例如 ActiveMQ 與任何 RDBMS 或 Oracle AQ 與 Oracle 資料庫位於同一位置)。這個模式的優點是極強的魯棒性和卓越的效能。

樣例程式碼更新

由於 Spring 版本的新版本和其他元件的釋出,本文提供的示例程式碼將不可避免地過時。請參閱 Spring 社群網站以訪問作者的最新程式碼,以及 Spring Framework 和相關元件的最新版本。

Full XA with 2PC 是通用的,並且總是有最高的置信度、最強的保護以防止在使用多個不同資源的情況下發生故障。缺點是,這個模式很昂貴,因為協議規定了額外的 I/O(但不要寫,直到你嘗試它),還需要特殊用途的平臺。有開源 JTA 實現了這種模式,可以提供擺脫應用程式伺服器的方法,但許多開發人員仍然認為這種方式是次優的。當然,更多人沒有花時間思考他們系統中的事務邊界就選擇了使用使用 JTA 和 XA。至少如果他們使用 Spring,他們的業務邏輯就不需要知道事務是如何被處理的,因此可以延遲平臺選擇。

Dr. David Syer 是 SpringSource 的首席顧問,常駐英國。他是 Spring Batch 專案的創始人和首席工程師,Spring Batch 是一個用於構建和配置離線和批處理應用程式的開源框架。他經常主持關於企業 Java 和行業評論員的會議。最近的出版物可以在 The Server Side, InfoQ 和 SpringSource 部落格找到。

更多參考資料

如果發現譯文存在錯誤或其他需要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可獲得相應獎勵積分。文章開頭的 本文永久連結 即為本文在 GitHub 上的 MarkDown 連結。


掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章