首先是不建議採用XA兩階段提交方式去處理分佈式事務,要知道要可以支持XA分佈式事務,必須是要實現XA規範才能夠,而Service自己是無狀態的,若是這樣去作了等因而把Service內部的東西暴露了出去。對於分佈式事務最好的方式仍是事務補償或者BASE基於消息的最終一致性。
能夠設想一個最簡單的分佈式事務場景,對於跨銀行的轉帳操做,該操做涉及到調用兩個異地的Service服務,一個是本地提供的取款服務,一個是目標銀行提供的存款服務,該兩個服務自己無狀態且獨立,構成一個完整的事務。對於事務的處理初步分析:
事務補償機制
事務補償即在事務鏈中的任何一個正向事務操做,都必須存在一個徹底符合回滾規則的可逆事務。若是是一個完整的事務鏈,則必須事務鏈中的每個業務服務或操做都有對應的可逆服務。對於Service服務自己無狀態,也不容易實現前面討論過的經過DTC或XA機制實現的跨應用和資源的事務管理,創建跨資源的事務上下文。所以也較難以實現真正的預提交和正式提交的分離。
在這種狀況下以上面例子來講,首先調用取款服務,徹底調用成功並返回,數據已經持久化。而後調用異地的存款服務,若是也調用成功,則自己無任何問題。若是調用失敗,則須要調用本地註冊的逆向服務(本地存款服務),若是本地存款服務調用失敗,則必須考慮重試,若是約定重試次數仍然不成功,則必須log到完整的不一致信息。也能夠是將本地存款服務做爲消息發送到消息中間件,由消息中間件接管後續操做。
在上面方式中能夠看到須要手工編寫大量的代碼來處理以保證事務的完整性,咱們能夠考慮實現一個通用的事務管理器,實現事務鏈和事務上下文的管理。對於事務鏈上的任何一個服務正向和逆向操做均在事務管理和協同器上註冊,由事務管理器接管全部的事務補償和回滾操做。
基於消息的最終一致性
在這裏首先要回答的是咱們須要時實時一致性仍是最終一致性的問題,若是須要的是最終一致性,那麼BASE策略中的基於消息的最終一致性是比較好的解決方案。這種方案真正實現了兩個服務的真正解耦,解耦的關鍵就是異步消息和消息持久化機制。
仍是以上面的例子來看。對於轉帳操做,原有的兩個服務調用變化爲第一步調用本地的取款服務,第二步發送異地取款的異步消息到消息中間件。若是第二步在本地,則保證事務的完整性基本無任何問題,即自己就是本地事務的管理機制。只要兩個操做都成功便可以返回客戶成功。
因爲解耦,咱們看到客戶獲得成功返回的時候,若是是上面一種狀況則異地卡立刻就能查詢帳戶存款增長。而第二種狀況則不必定,由於自己是一種異步處理機制。消息中間件獲得消息後會去對消息解析,而後調用異地銀行提供的存款服務進行存款,若是服務調用失敗則進行重試。
異地銀行存款操做不該該長久地出現異常而沒法使用,所以一旦發現異常咱們能夠迅速的解決,消息中間件中異常服務天然會進行重試以保證事務的最終一致性。這種方式假設問題必定能夠解決,在不到萬不得已的狀況下本地的取款服務通常不進行可逆操做。
在本地取款到異地存款兩個服務調用之間,會存在一個真空期,這段時間相關現金不在任何一個帳戶,而只是在一個事務的中間狀態,可是客戶並不關心這個,只要在約定的時間保證事務最終的一致性便可。
關於等冪操做的問題
重複調用屢次產生的業務結果與調用一次產生的業務結果相同,簡單點講全部提供的業務服務,不論是正向仍是逆向的業務服務,都必需要支持重試。由於服務調用失敗這種異常必須考慮到,不能由於服務的屢次調用而致使業務數據的累計增長或減小。
關因而否能夠補償的問題
在這裏咱們談的是多個跨系統的業務服務組合成一個分佈式事務,所以在對事務進行補償的時候必需要考慮客戶須要的是否必定是最終一致性。客戶對中間階段出現的不一致的承受度是如何的。
在上面的例子來看,若是採用事務補償機制,基本能夠是作到準實時的補償,不會有太大的影響。而若是採用基於消息的最終一致性方式,則可能整個週期比較長,須要較長的時間才能給獲得最終的一致性。好比周六轉款,客戶可能下週一才獲得通知轉帳不成功而進行了回退,那麼就必需要考慮客戶是否能給忍受。
其次對於前面討論,若是真正須要的是實時的一致性,那麼即便採用事務補償機制,也沒法達到實時的一致性。即極可能在兩個業務服務調用中間,客戶前臺業務操做對持久化的數據進行了其它額外的操做。在這種模式下,咱們不得不考慮須要在數據庫表增長業務狀態鎖的問題,即整個事務沒有完整提交併成功前,第一個業務服務調用雖然持久化在數據庫,可是仍然是一箇中間狀態,須要經過業務鎖來標記,控制相關的業務操做和行爲。可是在這種模式下無疑增長了整個分佈式業務系統的複雜度。數據庫