微服務架構中分散式事務實現方案怎樣何取捨

奈學教育發表於2020-06-08

提起微服務架構,不可避免的兩個話題就是服務治理和分散式事務。資料庫和業務模組的垂直拆分為我們帶來了系統效能、穩定性和開發效率的提升的同時也引入了一些更復雜的問題,例如在資料一致性問題上,我們不再能夠依賴資料庫的本地事務,對於一系列的跨庫寫入操作,如何保證其原子性,是微服務架構下不得不面對的問題。

1 分散式事務解決方案

針對分散式系統的特點,基於不同的一致性需求產生了不同的分散式事務解決方案,追求強一致的兩階段提交、追求最終一致性的柔性事務和事務訊息等等。各種方案沒有絕對的好壞,拋開具體場景我們無法評價,更無法能做出合理選擇。在選擇分散式事務方案時,需要我們充分了解各種解決方案的原理和設計初衷,再結合實際的業務場景,從而做出科學合理的選擇。

2 強一致解決方案

2.1 兩階段提交

兩階段提交演算法中有兩種角色:事務協調者和事務參與者,一個事務一般會涉及多個事務參與者,具體的兩階段過程如下圖所示:

第一階段:寫庫操作完成後協調者向所有參與者傳送Prepare訊息,詢問各參與者的本地事務是否可以提交,參與者根據自身情況向協調者返回可以或不可以;

第二階段:協調者收到所有參與者的反饋後,如果全部返回的是可以提交則向所有參與者傳送提交事務命令。只要有一個參與者返回的是不能提交,則向所有參與者傳送回滾命令。如下圖所示:

圖1 兩階段提交

在上述的兩階段模型中,事務提交過程中有可能出現協調者或個別參與者當機的情況,但多數情況下參與事務的節點可以透過詢問其他節點得知事務狀態,做出正確的操作。但在極端情況下事務有可能處於未知狀態。我們分析下下面這個場景:當協調者傳送提交指令後當機,而唯一收到提交指令的參與者完成提交後也當機了,此時沒有節點知道事務應該提交還是回滾,事務處於未知狀態,所以在這種極端情況下可能造成資料的不一致。針對兩階段的缺陷,又提出了三階段提交協議。

2.2  三階段提交

三階段提交是將第二階段拆分成預提交和確認提交兩個階段。這樣在事務提交過程中,無論哪個節點當機,只要有一個存活節點處於預提交或是提交狀態我們都可以確定事務是可以提交的(第一階段已經確認事務可以提交),反之如果沒有處於這兩種狀態的節點,則回滾事務。

圖2 三階段提交

從上面的分析可以看到,無論是兩階段還是三階段最後的“提交”都是一個耗時極短的操作,即使在分散式系統中失敗的機率也是非常小的,所以我們可以認為兩階段提交基本能夠保證分散式事務原子性。

3 落地方案

上面介紹的只是理論基礎,XA規範就是基於兩階段提交的理論模型提出的分散式事務規範,規範中的資源管理器相當於事務參與者;事務管理器相當於事務協調者,目前很多主流的關聯式資料庫都實現了XA介面。

落地到實際應用中我們會發現兩階段提交存在的一些問題:

1. 資料庫產品要保證資料完成性,寫入需要加鎖,所以在整個分散式事務協調過程中可能造成資料庫資源鎖定時間過長,不適合併發高以及子事務生命週期較長的業務場景;

2. XA規範要求事務管理器本地記錄事務執行狀態,所以事務管理器作為有狀態服務不支援事務異地恢復;

XA能夠最大程度保證資料的一致性,但在高併發場景下效能衰減非常嚴重,所以在資料一致性需求上如果不是“強一致”,不建議使用。

3.1 最終一致性解決方案

在我們大多數的業務場景中,追求的都是資料的最終一致性,業界也提出了很多柔性事務的解決方案,可以很大程度上保證資料的一致性,我們可以根據實際場景來權衡使用。具體的解決方案有很多,總結其設計思路可以分為下面3種模型:

3.1.1 TCC(Try-Confirm-Cancel)

TCC將事務分為Try,Confirm,Cancel三個階段。

1. Try階段:嘗試執行業務,預留資源;

2. Confirm階段:確認執行業務,使用Try階段資源;

3. Cancel階段:取消執行業務,釋放Try階段預留的資源;

我們用一個轉賬匯款的業務場景,說明下TCC的具體過程。例如:張三給李四轉賬100元,一次轉賬業務由兩個本地事務組成:1、張三賬戶扣減100元;2、李四賬戶增加100元。

事務成功處理流程如圖3:

圖3 Try-Confirm事務成功處理流程

事務失敗處理流程如圖4:

圖4 Try-Cancel事務成功處理流程

Try階段:

1、檢查張三賬戶,滿足要求賬戶扣減100元,記錄扣減事件(預留資源);

2、檢查李四賬戶有效性;

Confirm:

如果Try成功,李四賬戶增加100元,事務完成;

Cancel:

如果Try失敗,張三賬戶增加100元,刪除扣減事件記錄(釋放預留資源),事務取消。

從效能角度分析,TCC過程沒有對資源加鎖,對系統併發效能幾乎沒有影響,只是會有些額外輔助操作。需要注意,在這個模型中要保證資料一致性有兩個技術難點需要解決:

1. 需要有類似事務管理器的角色保證TCC過程的完整性;

2. Confirm和Cancel方法需要保證冪等(由於不可避免的重試操作必須要保證冪等);

TCC對業務侵入非常大,對RD同學十分不友好,業務改造成本相當高。

3.1.2 SAGA模型

SAGA模型把一個分散式事務拆分為多個本地事務,每個本地事務都有相應的執行模組和補償模組,當事務中任意一個本地事務出錯時,可以透過呼叫對應的補償方法恢復之前的事務,從而達到資料的最終的一致性。SAGA的事務管理器負責在事務失敗時執行補償邏輯,可以透過呼叫執行模組的逆向操作(例如執行子事務時同時生成逆向SQL)或呼叫業務開發人員提供的補償方法(需要保證補償的冪等性)來實現。

可以看到,SAGA雖然對業務造成一定的侵入,但當相對TCC已經有好很多了,而且,事務管理器理論上可以做到向後補償(撤銷所有已完成操作,恢復到事務開始狀態)或向前補償(繼續完成未完成事務,使業務請求得到成功處理,更符合業務預期)。

3.1.3 MQ事務訊息

MQ事務訊息對分散式事務模型進行了簡化,重點不再是保證所有子事務的原子性,而是保證本地事務和傳送MQ訊息的原子性,我們可以利用這一特點,將分散式事務轉化成本地事務和若干傳送MQ訊息的操作,然後要求消費方確保消費成功。利用MQ事務訊息,在系統中去掉了TCC和SAGA方案中的事務管理器角色,簡化了分散式事務模型,同時這也是對業務侵入最低最友好的方案(不用提供補償介面)。

當然這裡也有兩個基本前提:

1. MQ系統保證訊息能不丟失;

2. 消費方確保消費冪等(保證不丟失,就很難避免重複消費)。

需要注意的是,MQ事務訊息簡化了事務模型、降低了業務侵入,所以對資料一致性的保證保障也就相對比較低了。

4. 總結

柔性事務解決方案中,雖然SAGA和TCC看上去可以保證資料的最終一致性,但分散式系統的成產環境複雜多變,某些情況是可以導致柔性事務機制失效的,所以無論使用那種方案,都需要最終的兜底策略,人工校驗,修復資料。

我們綜合對比下幾種分散式事務解決方案:

一致性保證:XA > TCC = SAGA > 事務訊息

業務友好性:XA > 事務訊息 > SAGA > TCC

性 能 損 耗:XA > TCC > SAGA = 事務訊息

最後,在設計系統時我們一定要結合業務自身的一致性需求,選擇恰當的方案。可以看到對資料一致性保障越高的方案其開發成本、維護難度和系統效能損耗就越大,一定不要一味的追求高大上的方案,對系統過度設計。

更多免費技術資料及影片

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69976011/viewspace-2696932/,如需轉載,請註明出處,否則將追究法律責任。

相關文章