我的兩部分系列文章中的第一篇文章討論了在定義及執行面向服務的體系架構中的復雜業務事務時的固有難點。作為解決此難題的一個手段,我們引入了事務協調服務(Transaction Coordination Service,TCS)的概念,原則上,它可以用于管理安全的且一致的分布式事務。此處是第二部分,我將介紹一個 TCS 的原型設計,包含 Java 開發的示例代碼。此原型可以部署到任何 J2EE 容器中,并展示為 Web 服務。
此外,該原型闡明了一個用于由 XML 定義文件建立事務的潛在解決方案,用串行或并行的方式控制業務操作的執行和結束。我在最后以一個對可以實現來提供完整的(雖然很簡單)基于服務的事務管理系統的附加功能的討論作為結束。
事務協調服務框架
在分布式的、無狀態,且透明的環境中的事務管理,以及作為面向服務的體系架構(Service-Oriented Architecture,SOA),呈現出明顯的困難。SOA 底層的體系架構直接與確保關鍵業務操作完整性的需求是沖突的,該體系架構中,服務應該是無狀態的,廣大用戶可以訪問到的松耦合的業務操作。當事務廣泛地分布在也許能或也許不能參與標準的、兩階段提交事務的商業伙伴系統時是尤其正確的。因此,必須找出某種方法來協調分布式的業務服務,以便請求者可以將多個不同的業務功能(也就是,Web 服務)組合成集成的業務操作。目前,有許多主機和微型計算機的事務處理和監控系統,例如,IBM Customer Information Control System (CICS) 和 Microsoft Distributed Transaction Coordinator (MDTC),并且事務管理包含于所有的認證的 J2EE 實現中,例如 WebSphere Application Server。與下面給出的原型相比,這些方法中的原則差別與面向服務的體系架構的性質有關 —— 也就是,許多服務是“察覺不到事務的”。這需要一個稍微不同的分布式管理方法來確保全部事務的完整性。同樣,這里介紹的原型表現出復合的事務,其中有許多并行的操作,經常異步發生,并且需要在長期的持續時間內維持狀態的能力。
在第一部分中,我揭示了事務協調服務(TCS)的概念,它能夠管理以下與面向服務的體系架構中的分布式事務管理相關的情況:
TCS 包
如圖 1 所說明的,組成 TCS 原型的類放入四個包中:transaction 包、service 包、utility 包,和 exception 包。
Transaction 包中包含所有事務管理類,包括四個表示核心事務處理的類:
圖 1:原型事務協調服務(TCS)框架
另外,事務包包含三個枚舉類:TransactionIsolation、TransactionStatus,和 TransactionType。它們用于指示執行的隔離級別(例如,"no phantom reads" 或 "ANOMALY_SERIALIZED")、操作的當前狀態(例如,"PENDING-COMMIT"),和當前執行的事務類型(例如,"SERIALIZED" 或 "PARALLEL")。
Service 包包含一個類SOARemoteService,它實現了 ManagedCommitter 接口并控制與 SOA Transaction Definition 文件(參見圖 2 的實例)中定義的遠程服務交互的細節。
Utility 包包含 XML 解析器及用于構造基于 SOA Transaction Definition 文件(圖 2)的事務管理器的事務構造器類。原型使用 SAX 解析器機制 1 和構造器模式來執行該任務。
圖 2:示例 SOA Transaction Definition 文件
點擊此處放大
還有一個類,用來為 SOA Transaction Manager 和每個所含的 SOA Transaction 生成獨特的標識符,用于跟蹤事務重試和恢復。
最后,exception 包包含 SOAException 基類。它用于記錄錯誤條件并觸發事務重試和恢復邏輯。要使得框架簡單,所有附加的 SOA 錯誤處理都將作為繼承此基類的子類。
事務構造器如何工作
調用 loadTransaction()方法(在完成實現中,將作為一個 Web 服務)及一個格式明確的 SOA Transaction Definition 文件來執行 TCS 的初始化。如圖 3 所示,SOATransactionBuilder 類向 SOAXMLParser(SAX 解析器包裝類)注冊,作為內容處理器并且接受或解釋 SAX 解析事件來構建SOATransactionManager使用的SOATransaction列表。每個SOATransaction由一個 SOARemoteService 對象(實現了ManagedCommitter 接口 2 )集合構成,依次由服務調用信息(例如,服務 URL)、必要數據輸入消息,和數據映射信息構成。
圖 3:SOA 事務構造器
圖 4 說明了事務構造器進行的操作序列,包括初始服務調用,隨后是 SAX 解析所提供的 XML 文檔,以及構建 SOA 遠程服務對象和 SOA 事務對象。
圖 4:SOA Transaction Manager Builder 序列圖
點擊此處放大
事務管理器
組成事務管理器,形成原型事務協調服務(TCS)核心的三個類是 SOARemoteService、SOATransaction,和 SOATransactionManager。圖 5 中顯示了這三個類之間的關系,以及支持類和枚舉。SOATransactionManager 包含兩列 SOATransactions,一個用于串行執行,一個用于并行執行。所有的串行事務是按順序執行的,所以它是一個先進先執行的管理 3 。根據特性,并行操作可以按任何順序發生,因此,不存在那種對并行事務集合執行的限制。在一定時刻,可能有多于一個 SOATransactionManager在執行,但如果 SOARemoteService 對象不能夠支持并發控制,那么也許會導致并發問題。
如圖 5 中所示,SOATransactionManager 負責建立事務邊界("begin" 和 "end"),以及初始化對每個 SOATransaction 的執行級聯。注意到,事務隔離級別是在事務管理器層定義的。這是要確保所有的事務都在同一個“場地”上執行,也就是說,事務的隔離不會比另一個高或低。
圖 5:SOA Transaction Manager 類圖
點擊此處放大。
SOATransaction 類包含一個 ManagedCommitters(由SOARemoteService 類在原型中實現)的列表,它是按照 SOA Transaction Description 文件中定義的順序執行。如圖 6 所示,每個 SOATransaction 將在每個 ManagedCommitter 上執行準備、執行、提交/回滾,和結束步驟,利用圖 5 中左邊顯示的 TransactionStatus 枚舉類來跟蹤事務的狀態。如果任何 ManagedCommitters 報錯,SOATransaction 將向集合中的每個對象發出回滾命令,確保整個事務的完整性。
按照必要的步驟執行 SOARemoteService,連接到已定義的服務,映射所有事務環境信息,生成輸出消息,接收輸入消息,并且通常管理遠程服務調用的資源 4 。由于 SOARemoteService 對象需要實現 ManagedCommitter 接口,所以該調用的服務必須能夠處理“回滾”命令(參見圖 5 中 SOARemoteService 屬性中的 transAware 布爾值)。在無狀態服務的情況下,需要定義可以逆轉變更的補償服務調用。在此原型中,SOARemoteService 假定了遠程服務提供了 Web Services Description Language (WSDL) 文件,來定義輸入消息、輸出消息,和綁定信息。
圖 6:SOATransactionManager 序列圖
實現細節
注意:我沒有承諾任何關于原型代碼的性能、準確性,或完整性的內容!其目的是為了幫助闡明 TCS 的實現細節,而不是創建一個產品級品質的組件。如果您 1) 對開始一個項目感興趣,并且 2) 愿意將其變為通用的有用框架,我邀請您聯系我。
原型 TCS 已經由 Java (5.0) 實現,以及 JUnit 測試用例、Apache Ant 構建文件,和實例配置文件。Eclipse IDE 作為開發環境,并且所需要的庫包含于 lib 目錄中。實例使用了許多開源包,來生成 Universal Unique Identifier (UUID) 5 、SOA Transaction Definition 文件的基于 Xerces SAX 2.0 的解析 6 ,和標準 J2EE 運行時庫(用于部署到 J2EE 容器中)。如果您在系統上安裝了 Ant 的最新版本,那么所包含的 Ant 構建文件應該可以工作的很好 —— 但我不作任何保證!原型不包含作為 J2EE 會話 bean 來為中間部分的服務來部署所需要的代碼,但其大部分是機械的操作, SOATransactionManager 生成本地/遠程接口類,EJB (Enterprise JavaBeans) 描述符,和 JAR (Java Archive) 文件,并按 Web 服務部署此代碼到一個合適的容器中(留給讀者做練習 7 )。兩個單元測試 XMLParserTest 和 TransactionTest,是基于 JUnit 測試框架的。這兩個測試獲得所提供的示例 SOA 定義文件(CreateItineraryTransaction.xml),并分別輸出分析操作結果,或事務執行。當然,由于所提供的服務不存在,所以 SOARemoteService 的實現僅僅對 execute() 操作返回真。
源代碼包還包含由原型代碼生成的 Javadoc 文件。這些提供了便捷的方式來觀察完整的代碼基礎并且參考本文中我所包含的模型視圖中沒有充分說明的具體類信息。
那么遺漏了什么?
簡單地說:許多。我有意地省去了好幾個通常對產品級質量的服務很關鍵的條目,著重于事務管理工具的工作。但我沒有忘記它們!因此在最后一部分,我將討論所描述的框架能夠/應該如何擴展,以支持 TCS 余下的特性。
安全性
明顯的是,安全性是安全的事務管理服務中的關鍵部分。安全的 SOA 遠程操作本身是一個非常復雜的問題,并直接影響所有 TCS 實現。然而,存在一些相對簡單的方法來處理 TCS 和任意受管理服務之間的安全通道。第一個是利用協議,例如 SSH (Secure Shell) 或 HTTPS 來在 TCS 和所定義的服務提供者之間創建加密的套接字。這將幫助確保通道相當安全,而不受侵入。然而,這不能滿足服務層的驗證和授權的需求。由于大多數服務是無狀態的,所以每次調用服務的時候就需要執行驗證 —— 一個非常費時的過程。作為一個潛在的解決方案,安全標識可以作為初始SOARemoteService prepare() 調用的一部分被生成,在事務生命周期內對從服務提供者來的每個服務都是有效的。使用SOATransactionContext 可以將此安全性標識傳遞給ManagedCommitter 集合中的每個事務。另一種選擇,安全證書可以在構造時發給 SOATransaction,可以對當前事務會話有效。最后,可以使用一個聯合的方法,當服務提供者與其他提供者建立一個“信任環”時,例如如果 SOARemoteService 向一個提供者注冊,所有其他的都認同此安全標識(本質上,“單點登陸”的形式)。
資源管理
就 TCS 而言,主要的資源管理問題涉及處理在事務操作過程中超時的服務。例如,考慮一個串行的事務,它發布了一個 commit() 給許多被執行的SOARemoteServices,然后延遲了,由于 TCS 服務器上的負載,發送剩下的 commit() 調用要相當長的時間。如果由 SOARemoteService調用的服務實現服務級超時 —— 并且它們應該,在事務管理器失敗的情況下允許釋放所持有的資源 —— 那么可能做到的是,對于 SOATransactionManager,在碰到已經超時之前向許多業務功能發布 commit() 調用,使事務處于不一致狀態(例如 COMMIT_FAIL TransactionState,如圖 5)。要防止此情況,事務超時應該總是比包含服務調用的 shortest 少,這定義在對每個服務的示例 SOA Transaction Definition 文件中(參見圖 2 中包含 «service ... timeout="60" .../»的代碼行)。
并發控制
并發控制在業務事務術語中通常涉及生成和維護數據存儲上的鎖,例如關系數據庫。在事務執行的過程中,這些鎖確保對特定數據項的操作不會被其他同時發生的操作覆蓋掉。然而,如上面提到的,對于資源管理,必要的是,任何使用并發控制的服務都能夠在失?。ɡ?,超時)的情況下最終釋放那些鎖,這是為了避免將數據置于意外的,或不一致的狀態。此外,有許多不具備并發控制的服務,這也可能導致不一致的數據。由于這是一個服務層的功能,TCS 為確保并發而能做的非常少,除了查看是否有影響同樣數據記錄的并行事務,如果有,發布一個數據沖突可能出現的警告。
恢復/重試
事務失敗,這是如同宇宙熱寂一樣不可避免的。因此,任何具有完整特性的 TCS 都應該有一個工具來存儲失敗的事務,用于隨后的重試。有兩種考慮的方法。第一種是“有保證的交付”事務,將事務發送給 TCS,并期待在整體過程中,直到成功之前都將重試。這要求將事務存儲在持久的數據存儲器中并安排未來的重試嘗試。TCS 事務管理器隨后會在所有要素都成功執行的時候獲取并重試整個事務。事務恢復的另一個種類是“最佳努力”執行,在確定事務是失敗的且發布回滾命令之前,事務將重試 ManagedCommitter 許多次。
嵌套
本文中所介紹的原型 TCS 沒有實現任何形式的事務嵌套,在嵌套中,一個完整的事務是另一個事務的“子”事務,并且“父”事務依賴于所有孩子的成功執行。允許嵌套會導致內部事務成功,但父事務仍舊可以失敗的情況 —— 那么您如何回滾先前提交了的子事務呢?
目前的實現提供一個服務,可以遞歸地調用 TCS 來建立其自己的事務。這樣,如果初始的事務調用了 Service X,它可以使用另一個 TCS 實例為 Service Y、Q,和 Z 建立一個事務。一旦此事務成功了,Service X 向原有的 TCS 報告成功。此方法仍舊存在著問題,Service X 在原有 TCS 通知 Service X 提交(換句話說,子事務在父親完成前提交)之前已經提交了變更,但可能做到的是撰寫 TCS,使其考慮到暫停/恢復一個事務來說明 Service X 的執行調用及其提交調用之間的延遲。如您從此簡要討論中看到的,嵌套通常是復雜、混亂,且危險的,所以通常最好盡可能避免它。
結束語
在本文中,我介紹了使用事務管理器控制一組事務的分布式事務協調服務的原型實現。事務包含一組受管理的,執行準備、執行,和提交/回滾事務操作的提交者。雖然,對于此組件還有許多余下的特性可以實現,但是我希望我為那些處理 SOA 系統來開發和管理分布式事務的架構師或設計人員提供了有用的框架。
分布式的,可交互服務的 SOA 方法對解決許多企業整合的困難有著誘人的承諾。服務可以呈現給消費者 —— 不論是組織內部或外部的 —— 使用相同的接口和連通協議。利用標準的協議(例如,XML),將數據在定義明確的、獨立于平臺的協議上傳輸。然而,許多問題目前仍舊阻礙了 SOA 方法的廣泛采用,其中一個是復雜業務事務的建立和管理。我希望我的這個兩部分的文章能夠對您了解 SOA 的事務管理部分有所幫助,并提供一些有用的采用指導。
注釋
1SAX(Simple API for XML)解析器是單向的 XML 閱讀器,獲得定義明確的 XML 文件并生成關鍵事件,例如標簽、屬性,和字符文本。XML 解析器的另一個形式是基于 DOM(Document Object Model)的,它形成了完整 XML 結構的內存中的對象模型。對于此實例,我選擇更加簡單且更加快速的 SAX 實現。
2ManagedCommitter 只實現了 OpenGroup(www.opengroup.org)為兩階段提交處理所定義的部分 XA 接口。這是為了避免說不清楚具有太多的細節的原型。在 TCS 的產品版本中實現完整的 X/Open 規范將是直接了當的。
3 更成熟的方案可以使用一個優先級分數來確定執行順序,但原型的主要目標是簡單明了。
4初始原型定義了 SOALocalService 和一個 SOARemoteService 類,顯示出可以使用與遠程服務完全一樣的方式來調用本地資源,SOALocalService 對象從當前原型中略去了,為了強調協調遠程服務的細節。
5 該類使用了 UUID 生成引擎(參見 Tatu Saloranta: http://jug.safehaus.org)的 JUG 實現。
6 http://xerces.apache.org
7 您不會討厭作者這樣做吧?