BizTalk Server 事務機制

概述

 

BizTalk Server 業務流程引擎可管理複雜流程和/或事務集的狀態,對其應用業務邏輯,並調用其支持應用程序。

業務流程可由使用原子事務的若干分立工作組成,這些原子事務在發生錯誤或長時間運行時自動回滾所有更改,業務流程可包含嵌套事務,並可使用自定義異常處理從錯誤中恢復。這些事務性語義通常由業務流程設計器中的“作用域”構造管理。

長期流程可持續數天、數週,甚至更長的時間。長期流程通常利用相關將收到的消息和要發送的消息關聯起來。業務流程引擎通常會凍結這些實例以節省系統資源,並在收到相關消息後解除凍結。業務流程引擎會在已知檢查點處將業務流程狀態持久化到 MessageBox 數據庫,以便爲從任何應用程序異常或系統異常中恢復做好準備。

提供給 BizTalk 業務流程引擎的事務性編程模型不僅支持異常處理,還支持從失敗的事務、在錯誤發生時自動回滾其操作的原子事務或包含其他事務的長期事務及自定義異常處理中恢復。

 

原子事務

 

BizTalk 業務流程可設計爲按照事務的傳統“ACID”概念,執行不同部分的工作。在執行時,這些離散的或原子的工作單位會將業務流程從一個一致的狀態轉移到獨立於其他工作單位的一致且持久的新狀態。這通常是使用“作用域”構造實現的,作用域構造使用事務性語義封裝這些工作單位。也可以將整個業務流程定義爲一個原子事務,而不使用作用域。但是,這些作用域不能標記爲事務性的,除非業務流程本身標記爲長期或原子事務類型。原子事務保證在事務性更新期間發生故障時可自動回滾任何部分更新,並且消除事務的影響(事務中進行的任何 .NET 調用的影響除外)。BizTalk 業務流程中的原子事務與分佈式事務處理協調器 (DTC) 事務大體相似,只是前者通常存活時間較短並且具有四個“ACID”屬性(原子性、一致性、隔離性和持久性):

  • 原子性
    一個事務就表示一個原子的工作單位。要麼在事務內執行所有修改,要麼不執行任何修改。
  • 一致性
    在提交時,事務必須在系統內保持數據的整體性。如果某一事務在該事務開始前對已在內部保持了一致的數據庫執行數據修改,則在提交該事務時,數據庫仍必須在內部保持一致。確保此屬性的工作主要由應用程序開發人員負責。
  • 隔離性
    並行事務進行的修改必須與其他並行事務進行的修改隔離。並行運行的隔離事務所執行的修改將保持內部數據庫一致性,與順序運行事務完全一樣。
  • 持久性
    在提交某一事務後,默認情況下所有修改都永久存在於系統中。即使系統發生故障,這些修改也存在。

在 BizTalk 業務流程中使用的原子事務支持以下隔離級別:

  • 提交讀
    在正在讀取數據時保持共享鎖,以避免髒讀,但是在事務結束之前可以更改數據,從而導致不可重複的讀取或幻像數據。
  • 可重複讀
    在查詢中使用的所有數據上放置鎖,以防止其他用戶更新這些數據。這防止了不可重複的讀取,但仍有可能產生幻像行。
  • 可序列化
    放置一個範圍鎖,防止在事務完成前其他用戶更新行或將行插入數據庫中。

BizTalk Server 確保原子事務內的狀態變化(例如對變量、消息和對象的修改)只在事務提交後在原子事務的作用域外可見。中間狀態的變化將與業務流程的其他部分隔離開來。

如果要求對數據具有完全的 ACID 屬性(例如,數據必須獨立於其他事務),則必須只使用原子事務。

在原子事務失敗時,所有狀態都將重置,就像業務流程實例從來沒有進入該作用域。BizTalk 針對原子事務的規則是:所有變量(而不只是作用域的本地變量)都參與該事務。在原子事務中使用的所有非序列化變量和消息都應聲明爲對作用域而言是本地的;否則,編譯器將顯示“變量…未標記爲可序列化”錯誤。所有原子作用域都將認爲是“同步的”,並且如果實際上將同步的關鍵字用於原子作用域,則業務流程編譯器將對冗餘的使用發出警告。共享數據的同步將從作用域開始一直擴展到作用域成功完成(包括在作用域結束時的狀態持久化),或者擴展到異常處理程序完成時(如果出現錯誤)。同步域並不擴展到補償處理程序。

原子事務可與超時值(此時,業務流程將停止事務並且實例將掛起)相關聯。如果某一原子事務包含接收形狀、發送形狀或啓動業務流程形狀,則相應操作將不會在提交該事務前發生。

如果用戶故意引發 RetryTransactionException,或者在原子事務嘗試提交時引發 PersistenceException,原子事務將重試。例如,如果原子事務是分佈式 DTC 事務的一部分,而該事務中的其他參與者停止了該事務,則可能會引發 PersistenceException。同樣,如果在事務正嘗試提交時存在數據庫連接問題,則也可能引發 PersistenceException。如果 Retry=True 的原子作用域發生此情況,則它將重試最多 21 次。默認情況下,每次重試之間的延遲爲 2 秒(但可以修改該默認值)。在執行完全部 21 次重試後,如果該事務仍無法提交,則掛起整個業務流程實例。該實例可以手動恢復,並且將從衝突的原子作用域的開始處使用新計數器重新開始。

 

DTC 事務

 

儘管原子事務在行爲上類似 DTC 事務,但默認情況下,它們並不是顯式的 DTC 事務。可以顯式地使這些事務成爲 DTC 事務,只要要在該事務中使用的任何對象都是從 System.EnterpriseServices.ServicedComponents 派生的 COM+ 對象,並且隔離級別在事務組件之間達成一致。

 

非序列化對象

 

如果想要在某一業務流程內使用非序列化對象,則必須只在原子事務內使用它。只要業務流程由引擎保存,在原子事務外使用此類對象都可能會導致數據丟失。

 

使用原子事務的方案

 

方案 1:具有 COM+ ServicedComponent 的原子事務

下面的業務流程顯示如何將 RetryTransactionException 與原子事務一起使用。儘管無法爲原子作用域直接包括異常處理程序,但該作用域可以包括可具有異常處理程序的非事務性作用域。ServicedComponent 在同一 DTC 事務中登記,捕獲由該組件引發的任何異常並重新引發爲 RetryTransactionException。(假定針對原子作用域將 Retry 屬性設置爲 True)。

請注意,即使未引發 RetryTransactionException,仍將掛起此業務流程,並將回滾 MessageAssignment 形狀中的操作。但是,這種模式能夠在自動進行重試的應用程序中提供一定的彈性。

具有COM+ ServicedComponent 的原子事務

方案 2:將事務性適配器與原子事務一起使用

下面的業務流程顯示如何將原子事務與 SQL 適配器一起使用。整個業務流程被標記爲長期業務流程,並且帶有分別用於工作的兩個邏輯部分的單獨原子事務:插入新客戶和插入客戶訂單詳細信息。

如果由於某種原因導致插入訂單的操作失敗,則應回滾插入客戶的操作。該示例使用 SQL 適配器執行數據庫工作。如前所述,消息發送到 MessageBox 數據庫時將完成與原子事務相關聯的作用域。這表示引擎在 Scope_InsertCustomer 和 Scope_InsertOrder 作用域中成功發送消息後,將提交每一作用域。SQL 適配器將爲客戶或訂單的實際插入創建一個新事務。

這些端口具有“送達通知”屬性,用來驗證是否通過發送端口成功發送了消息。將“送達通知”屬性設置爲“已傳輸”時,會在發送操作的事務性提交點之前放置一個接收訂閱。但是在原子作用域的情況下,會將接收訂閱放在封閉的父作用域中。

在 InsertOrder SQL 事務失敗的情況下,將發送回“Nack”並提交“Scope_InsertOrder”。發送端口用盡所配置的重試次數後,將引發DeliveryFailureException。將運行默認補償過程的默認異常處理程序會捕獲此異常。這將調用與Scope_InsertCustomer 和 Scope_InsertOrder 相關聯的補償處理程序,從而導致撤銷插入客戶信息的操作。

具有原子事務的事務性適配器

長期事務

 

長期事務是 BizTalk 業務流程中常用的重要構造。它們提供的功能可幫助實現自定義的基於作用域的補償、自定義的基於作用域的異常處理以及嵌套事務,因此,可以很靈活地設計可靠的事務結構。

如果事務可能需要長時間運行並且不需要完整的 ACID 屬性(即,不需要確保數據與其他事務隔離),則可以使用長期事務。長期事務可能具有較長的不活動時間,通常是由於等待外部消息到達造成的。

長期事務擁有一致性和持久性,但不具備原子性和隔離。長期事務內的數據不鎖定;其他進程或應用程序可以對數據進行修改。不保持狀態更新的隔離屬性,因爲保持長期鎖定不現實。

長期事務的提交不同於原子事務的提交。沒有針對結果的分佈式協調的隱式假定(長期事務僅存在於單個業務流程實例中)。而是在長期事務中的最後一個語句完成時,代表該事務已提交。事務中止的情況下,不會“自動”回滾狀態。這種回滾可以通過編寫異常處理程序和補償處理程序來實現。

作用域可通過聲明變量、消息和 .NET 組件,定義自己的狀態。長期事務能夠訪問自己的作用域的狀態信息、封閉它的任何作用域以及在業務流程內全局定義的任何狀態信息。長期事務不能夠訪問不封閉它的任何作用域的狀態信息。

 

嵌套

 

長期事務可以包含原子事務或其他長期事務。它們可以嵌套到任意深度。例如,的事務可以包含兩個其他的長期事務,這兩個事務又可以包含原子事務。

如果整體事務的一個或多個組件需要是原子的,而該整體事務又需要是長期的,則嵌套將很有用。讓我們看一下一個接收和履行採購訂單的例子。該採購訂單可能會在任何時候到達,並且履行訂單的不同步驟可能需要一定時間才能完成,但仍想要將整個過程作爲一個事務處理。顯然,此例子中的整體事務需要是長期事務,但對於個別步驟,例如確認付款,可能需要是原子的。

 

補償

 

長期事務可以指定某一補償模塊,此補償模塊將在事務提交後被調用以補償該事務的活動。它可能只是撤消事務(如果可能),或者執行以某種方式幫助減輕事務影響的某些其他功能(例如通知)。如果沒有添加自己的補償代碼,則默認情況下運行時引擎將調用內部事務的補償模塊,長期事務和原子事務都採用相反順序,即以最後提交的事務開始、以最先提交的事務結束。

 

容錯

 

事務支持容錯,以便從內部錯誤(例如機器故障和軟件錯誤)和外部錯誤(例如取消消息)恢復。在發生事務錯誤時,並不自動回滾長期事務內的部分更新,因爲它們位於 ACID 事務中。

在發生錯誤時將調用長期事務的異常代碼塊。異常代碼塊包含一組編寫的錯誤處理程序,用於處理在事務執行期間可能導致的任何錯誤。可以藉助消息、變量和對象的最後已知狀態來處理錯誤。

通常,將希望異常處理程序評估在發生異常時業務流程的狀態,基於該狀態採取任何必要措施,並且調用任何嵌套事務的補償。

在發生錯誤時,將中斷長期事務的執行。長期事務不能在發生錯誤後恢復。

 

使用長期事務的方案

 

方案 1:將長期事務用於超時

長期作用域可與某一超時關聯,超時是長期工作必須在此時間範圍內完成的邏輯時間。如果該作用域沒有在指定時間內完成,將引發預定義的系統異常 TimeoutException

您可以通過將整個業務流程標記爲長期的,或者通過讓外部長期作用域嵌套任何其他作用域,創建長期進程。在前一個方案中,系統提供的異常處理程序將運行,而後一個方案則允許特定的異常處理程序與外部作用域相關聯。默認的系統提供的異常處理程序將爲每個成功完成的嵌套事務性作用域(如果有)運行補償處理程序,運行順序與其完成順序相反。您可以通過在異常處理程序中將補償形狀用於長期事務,通過自補償實現同一任務。

下面的業務流程介紹如何將超時與長期事務相關聯。

具有超時值的長期事務

有時候,您可能需要連接以批處理形式操作的舊式系統。此方案顯示了一個要接收併發送到舊式系統的採購訂單。此舊式系統處理該採購訂單,並且發送回採購訂單確認。該發送操作採用採購訂單號初始化某一相關集,並且接收操作將遵循該相關集。該接收操作還處於具有超時值的長期作用域中。

業務流程引擎將凍結正等待接收的業務流程實例。相關將確保在接收消息後調用同一業務流程實例。如果該採購訂單確認在超時值指定的時間間隔內未到達,將引發 TimeoutException

方案 2:將長期事務用於自定義補償

以下業務流程闡釋如何關聯自定義補償以及調用與整個業務流程相關聯的自定義補償。此方案將插入一個新客戶以及插入該客戶的訂單明細。業務流程的邏輯規定如果訂單插入失敗,您應該回滾該客戶插入。該客戶插入可由舊式系統執行,因此,在單獨的可調用業務流程中闡釋。被調用的業務流程具有爲補償設置的 Custom 屬性,這將提供單獨的表格來執行補償過程。該補償是要刪除新插入的客戶。

調用業務流程具有要執行訂單插入的長期作用域。此作用域嵌套在某一外部長期作用域中。該外部作用域具有關聯的異常處理程序,以便捕獲任何異常。該處理程序使用補償形狀來定義與調用的業務流程相關聯的自定義異常,以便回滾在對業務流程的調用中可能發生的任何更改。

具有自定義補償的長期事務

調用的業務流程(主要)

調用的業務流程(補償)

 

業務流程中的持久化

 

業務流程引擎將保存業務流程實例在不同持久化點時的整個狀態,以便可以解除凍結業務流程實例。該狀態包括可在業務流程中使用的所有基於 .NET 的組件以及消息和變量。該引擎存儲處於以下持久化點時的狀態:

  • 事務作用域(原子事務或長期事務)結束時
  • 在調試斷點時
  • 在通過啓動業務流程形狀執行其他業務流程時
  • 在發送形狀上(原子事務中除外)
  • 在掛起業務流程實例時
  • 在系統以可控方式關閉時
  • 在引擎確定它要解除凍結時
  • 在業務流程實例完成時

引擎在持久化點佔用高昂系統資源(尤其是在處理大消息)時優化持久化點的數目。如下面的兩個業務流程實例所示,在原子作用域中含發送形狀的業務流程中,引擎確定事務作用域結束和業務流程結束之間的單個持久化點。在其他業務流程中,存在兩個持久化點,一個用於第一個發送形狀,第二個用於發送形狀外加業務流程結束。

業務流程持久化

在業務流程中使用的任何基於 .NET 的對象(無論是直接的還是間接的)都必須標記爲可序列化,但以下情況除外:對象在原子作用域中被調用,或者對象是無狀態的並且只通過靜態方法調用。System.Xml.XmlDocument 是特例,它不需要標記爲可序列化(與作用域的事務屬性無關)。

針對 System.Xml.XmlDocument 的特殊處理的工作原理:

在用戶定義 T 類型的變量 X 時,其中,TSystem.Xml.XmlDocument 或從 System.Xml.XmlDocument 派生的類,編譯器會將 X 視爲可序列化對象。

在序列化 X 時,運行時將保留以下信息片斷:(a) 對象 X 所引用的實際類型 Tr (b) 文檔的 OuterXml 字符串。

在對 X 執行反序列化時,運行時將創建 Tr 的一個實例(假定是不取任何參數的構造函數),並且將調用 LoadXml,向該實例提供保存的 OuterXml。X 將設置爲指向新創建的 Tr 實例。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章