分散式補償事務處理方案 / 分散式計算是如何控制事務的?
事務原子性,一致性,永續性,隔離性是基本的屬性,這裡不解釋,本篇文章只對分佈性事務方案做說明方案
問題來源
隨著分散式微服務應用盛行,帶來的優勢是顯而易見的,但是在面臨事務的時候,卻變的異常麻煩,因為是在不同的應用內,所以無法在單個應用內做回滾處理,這個時候,就需要有一個單獨的應用做補償性事務處理。由此引入本篇的內容,該內容配圖參考龍果學院開源支付系統
非同步確保性,確定訊息最終一致性
從圖中可以看到,業務對A訊息佇列進行處理,處理完成後,將處理狀態推送至B訊息佇列中,訊息恢復系統對這個AB兩個佇列進行對比,狀態為完成的訊息進行重新推送,或者資料恢復原始狀態
最大努力通知型
在小編遇到的大部分saas服務合作商中,大部分都屬於這種,及當沒有收到支付通知訊息時候,主動呼叫狀態查詢介面,去進行狀態更新,如上海的某生活繳費服務提供商
#### 附錄
雲棲社群:https://yq.aliyun.com/articles/69572
具體的技術實現方案,小編正在編碼中...
===============================================================================================================================
分散式計算是如何控制事務的?
不管是soa,還是微服務,我們做一個大的專案,會拆分成多個模組,也就是多個小專案。那我們這些小專案呼叫得時候,這個分散式事物是怎麼控制的,可以把dubbo和feignclient的都詳細講下嗎?
事務的管理不應該屬於Dubbo框架, Dubbo只需實現可被事務管理即可, 像JDBC和JMS都是可被事務管理的分散式資源, Dubbo只要實現相同的可被事務管理的行為,比如可以回滾, 其它事務的排程,都應該由專門的事務管理器實現。 在Java中,分散式事務主要的規範是JTA/XA, 其中:JTA是Java的事務管理器規範, XA是工業標準的X/Open CAE規範,可被兩階段提交及回滾的事務資源定義, 比如某資料庫實現了XA規範,則不管是JTA,還是MSDTC,都可以基於同樣的行為對該資料庫進行事務處理。
首先是不建議採用XA兩階段提交方式去處理分散式事務,要知道要能夠支援XA分散式事務,必須是要實現XA規範才可以,而Service本身是無狀態的,如果這樣去做了等於是把Service內部的東西暴露了出去。對於分散式事務最好的方式還是事務補償或者BASE基於訊息的最終一致性。
可以設想一個最簡單的分散式事務場景,對於跨銀行的轉賬操作,該操作涉及到呼叫兩個異地的Service服務,一個是本地提供的取款服務,一個是目標銀行提供的存款服務,該兩個服務本身無狀態且獨立,構成一個完整的事務。對於事務的處理初步分析: 事務補償機制 事務補償即在事務鏈中的任何一個正向事務操作,都必須存在一個完全符合回滾規則的可逆事務。如果是一個完整的事務鏈,則必須事務鏈中的每一個業務服務或操作都有對應的可逆服務。對於Service服務本身無狀態,也不容易實現前面討論過的通過DTC或XA機制實現的跨應用和資源的事務管理,建立跨資源的事務上下文。因此也較難以實現真正的預提交和正式提交的分離。
在這種情況下以上面例子來說,首先呼叫取款服務,完全呼叫成功並返回,資料已經持久化。然後呼叫異地的存款服務,如果也呼叫成功,則本身無任何問題。如果呼叫失敗,則需要呼叫本地註冊的逆向服務(本地存款服務),如果本地存款服務呼叫失敗,則必須考慮重試,如果約定重試次數仍然不成功,則必須log到完整的不一致資訊。也可以是將本地存款服務作為訊息傳送到訊息中介軟體,由訊息中介軟體接管後續操作。 在上面方式中可以看到需要手工編寫大量的程式碼來處理以保證事務的完整性,我們可以考慮實現一個通用的事務管理器,實現事務鏈和事務上下文的管理。對於事務鏈上的任何一個服務正向和逆向操作均在事務管理和協同器上註冊,由事務管理器接管所有的事務補償和回滾操作。
基於訊息的最終一致性 在這裡首先要回答的是我們需要時實時一致性還是最終一致性的問題,如果需要的是最終一致性,那麼BASE策略中的基於訊息的最終一致性是比較好的解決方案。這種方案真正實現了兩個服務的真正解耦,解耦的關鍵就是非同步訊息和訊息持久化機制。 還是以上面的例子來看。對於轉賬操作,原有的兩個服務呼叫變化為第一步呼叫本地的取款服務,第二步傳送異地取款的非同步訊息到訊息中介軟體。如果第二步在本地,則保證事務的完整性基本無任何問題,即本身就是本地事務的管理機制。只要兩個操作都成功即可以返回客戶成功。
由於解耦,我們看到客戶得到成功返回的時候,如果是上面一種情況則異地卡馬上就能查詢賬戶存款增加。而第二種情況則不一定,因為本身是一種非同步處理機制。訊息中介軟體得到訊息後會去對訊息解析,然後呼叫異地銀行提供的存款服務進行存款,如果服務呼叫失敗則進行重試。
異地銀行存款操作不應該長久地出現異常而無法使用,因此一旦發現異常我們可以迅速的解決,訊息中介軟體中異常服務自然會進行重試以保證事務的最終一致性。這種方式假設問題一定可以解決,在不到萬不得已的情況下本地的取款服務一般不進行可逆操作。 在本地取款到異地存款兩個服務呼叫之間,會存在一個真空期,這段時間相關現金不在任何一個賬戶,而只是在一個事務的中間狀態,但是客戶並不關心這個,只要在約定的時間保證事務最終的一致性即可。
關於冪等操作的問題 重複呼叫多次產生的業務結果與呼叫一次產生的業務結果相同,簡單點講所有提供的業務服務,不管是正向還是逆向的業務服務,都必須要支援重試。因為服務呼叫失敗這種異常必須考慮到,不能因為服務的多次呼叫而導致業務資料的累計增加或減少。 關於是否可以補償的問題 在這裡我們談的是多個跨系統的業務服務組合成一個分散式事務,因此在對事務進行補償的時候必須要考慮客戶需要的是否一定是最終一致性。客戶對中間階段出現的不一致的承受度是如何的。 3
在上面的例子來看,如果採用事務補償機制,基本可以是做到準實時的補償,不會有太大的影響。而如果採用基於訊息的最終一致性方式,則可能整個週期比較長,需要較長的時間才能給得到最終的一致性。比如週六轉款,客戶可能下週一才得到通知轉賬不成功而進行了回退,那麼就必須要考慮客戶是否能給忍受。
其次對於前面討論,如果真正需要的是實時的一致性,那麼即使採用事務補償機制,也無法達到實時的一致性。即很可能在兩個業務服務呼叫中間,客戶前臺業務操作對持久化的資料進行了其它額外的操作。在這種模式下,我們不得不考慮需要在資料庫表增加業務狀態鎖的問題,即整個事務沒有完整提交併成功前,第一個業務服務呼叫雖然持久化在資料庫,但是仍然是一箇中間狀態,需要通過業務鎖來標記,控制相關的業務操作和行為。但是在這種模式下無疑增加了整個分散式業務系統的複雜度。