漫談分佈式事務和接口冪等性


分佈式服務須要知足CAP原則,Consistency(一致性)、 Availability(可用性)、Partition tolerance(分區容錯性),但三者不可得兼;通常都會優先保證可用性和分區容錯性,而且保證最終一致性。BASE理論是對CAP原則的補充,Basically Available,Soft state,Eventually Consistent,也就是當CAP三者不能兼得的時候,能夠作到最終一致性。數據庫

 

大型應用通常須要作業務分拆以便於提高業務的可維護性和擴展性,但因爲業務分佈於多個系統中,數據天然也分佈於多個DB中,數據庫事務則再也不能知足業務需求。相比較於數據庫事務,分佈式事務須要考慮更多的可變因素,好比某一臺server沒有響應或者響應超時,網絡延遲等,所以通常會在分佈式事務中引入一箇中間協調者,用於協調多個事務參與者之間的狀態。
通常分佈式事務處理模式包括:2階段提交、3階段提交、TCC(Try-Confirm-Cancel)、可靠消息(消息隊列、數據庫表)、SAGAS長事務、補償性事務。具體採用哪種分佈式事務處理模式,須要根據本身業務場景來選擇合適的機制。緩存

 

#1 異步消息(MQ):網絡

異步方案用於保證最終事務一致性(Eventual Transaction Consistency),流程是MP在處理完業務以後發送一個消息到MQ裏,MC從MQ中獲取消息並進行處理,處理完畢以後向MP發送確認消息,爲了保證消息機制的可靠性MP和MC須要保證在各自系統內部的動做都在一個事務裏。優勢是流程簡單,MP能有很快的響應速度;缺點是沒有回滾機制,所以MP和MC的狀態有可能不一致;異步

#2 兩階段提交(2PC):分佈式

兩階段提交用於保證最終一致性,流程中須要有一個協調者,在pre-commit階段協調者觸發資源鎖定動做,commit或者rollback階段協調者進行實際的資源消費動做或者釋放動做;因爲時候多階段提交,因此每一次交互均可能出現異常,所以須要引入重試機制或者MQ機制。優勢是能夠將極大下降狀態不一致發生的可能;缺點是業務操做時同步阻塞,響應速度受影響,而且受單點問題影響。
2PC最大的問題在於當參與者比較多的時候,若是第一階段任意有一個參與者沒有及時響應的話全部參與者的資源都會被鎖定,因此在此基礎上第一階段分紅兩個小的階段,先發送一個詢問canCommit的消息,當全部參與方都響應了才進入preCommit進行資源鎖定,等全部的參與方都preCommit肯定以後,進入doCommit階段,同時全部的操做都會加入等待超時設置以保證數據一致性,這樣的設計就是3階段提交(3PC)。ide

 

#3 異步事務消息(RMQ):設計

異步事務消息用於保證最終一致性,流程更像是結合了異步消息和2階段提交的混合體,能夠解決MP的發送給MQ的消息若是沒有獲得處理或者處理失敗的場景,RMQ增強了對MQ的消息狀態管理和重試機制的實現;MP先發送一個pre-commit的消息給MQ,而後執行本地的事務,執行成功後給MQ一個確認消息,MQ收到消息後將消息狀態設置成ready,也就是MC能夠消費。 3d

 

#4 補償事務(CT)或TCC(Try-Confirm-Cancel):版本控制

針對每個操做,都註冊一個與之對應的補償操做,從而組成一個操做鏈和補償操做鏈;一旦操做鏈上某一步出錯後,就會按照補償操做鏈相反的順序進行執行;優勢在於不用提早鎖定資源,流程比較簡單;缺點是補償操做的界定範圍不明確容易形成狀態不一致。server

 

分佈式系統中接口的冪等性(idempotent)

分佈式系統中存在這樣的狀況,因爲網絡延遲,請求具備超時重試功能,MQ發送消息和RPC調用等,某個動做可能被執行屢次,但業務需求上不能接受接口方法被執行一次與執行屢次的結果狀態不一致,好比接口boolean withdraw(UUID account_id, Long amount)用於對指定帳戶扣款,若是執行屢次就會屢次扣款,這樣的結果是不能接受的,所以須要保證接口的冪等性。冪等性指的是對於一個接口而言若是參數相同,在特定業務場景下調用一次跟調用屢次的結果狀態都是相同的,所以上述接口若是聽從冪等性設計的話,則無論調用幾回,用戶帳戶的錢都只會被扣除一次。有多種冪等性的接口設計策略,如one-time-use token,全局惟一ID,多版本控制,狀態機控制等,實際須要根據具體的業務進行設計。


冪等性設計的基本原則是給業務請求分配一個惟一的ID,業務單元在處理業務請求以前須要判斷該業務請求是否被處理過,好比業務請求到達以後先判斷緩存系統中是否有ID的記錄,若是沒有則表示第一次請求,則正常處理業務消息並將ID存入緩存系統;若是有記錄則表示該業務請求已經被處理過,則忽略當前的業務請求;業務請求ID能夠有多種形式,對於本地事務而言DB的primary key能夠保證惟一性,對於分佈式事務而言須要根據業務進行設計。

接口boolean withdraw(UUID orderId, UUID account_id, Long amount, OrderStatus status, String token)相比以前的接口多了三個參數,token是事先從一個共享service中獲取,標識一次扣款操做,共享service會將這個token存儲於自身的DB中並保存狀態,orderId表示業務惟一性的ID,status表示針對orderId的狀態流轉,所以只要對於orderId操做過一次扣款操做以後,token標記的狀態就會更新(或者status就會更新成STATUS_PAID),這樣無論以後的有多少次操做都不會再次執行扣款的動做。

相關文章
相關標籤/搜索