天天看點

分布式事務最終一緻性常用方案

目前的應用系統,不管是企業級應用還是網際網路應用,最終資料的一緻性是每個應用系統都要面臨的問題,随着分布式的逐漸普及,資料一緻性更加艱難,但是也很難有銀彈的解決方案,也并不是引入特定的中間件或者特定的開源架構能夠解決的,更多的還是看業務場景,根據場景來給出解決方案。根據筆者最近幾年的了解,總結了幾個點,更多的應用系統在編碼的時候,更加關注資料的一緻性,這樣系統才是健壯的。

一、基礎理論

   目前關于事務的幾大理論包括:acid事務特性,cap分布式理論,以及base等。acid在資料庫事務中展現,cap和base則是分布式事務的理論,結合業務系統,例如訂單管理,例如倉儲管理等,可以借鑒這些理論,進而解決問題。

1、acid 特性

2、cap特性

c(一緻性)一緻性是指資料的原子性,在經典的資料庫中通過事務來保障,事務完成時,無論成功或復原,資料都會處于一緻的狀态,在分布式環境下,一緻性是指多個節點資料是否一緻;

a(可用性)服務一直保持可用的狀态,當使用者發出一個請求,服務能在一定的時間内傳回結果;

p(分區容忍性)在分布式應用中,可能因為一些分布式的原因導緻系統無法運轉,好的分區容忍性,使應用雖然是一個分布式系統,但是好像一個可以正常運轉的整體

3、base特性

ba: basic availability 基本業務可用性;

s: soft state 柔性狀态;

e: eventual consistency 最終一緻性;

二、最終一緻性的常用做法

分布式事務最終一緻性常用方案

1、單資料庫事務

      如果應用系統是單一的資料庫,那麼這個很好保證,利用資料庫的事務特性來滿足事務的一緻性,這時候的一緻性是強一緻性的。對于java應用系統來講,很少直接通過事務的start和commit以及rollback來寫死,大多通過spring的事務模闆或者聲明式事務來保證;

2、多資料庫事務

     針對多資料庫事務可以根據二階段送出協定,采用spring 3.0 + atomikos + jta進行支援;

3、基于事務型消息隊列的最終一緻性

     借助消息隊列,在處理業務邏輯的地方發送消息,業務邏輯處理成功後,送出消息,確定消息是發送成功的,之後消息隊列投遞來進行處理,如果成功,則結束,如果沒有成功,則重試,直到成功,不過僅僅适用業務邏輯中,第一階段成功,第二階段必須成功的場景。對應上圖中的c流程。

4、基于消息隊列+定時補償機制的最終一緻性

     前面部分和上面基于事務型消息的隊列,不同的是,第二階段重試的地方,不再是消息中間件自身的重試邏輯了,而是單獨的補償任務機制。其實在大多數的邏輯中,第二階段失敗的機率比較小,是以單獨獨立補償任務表出來,可以更加清晰,能夠比較明确的直到目前多少任務是失敗的。對應上圖的e流程。

5、異步回調機制的引入

     a應用調用b,在同步調用的傳回結果中,b傳回成功給到a,一般情況下,這時候就結束了,其實在99.99%的情況是沒問題的,但是有時候為了確定100%,記住最起碼在系統設計中100%,這時候b系統再回調a一下,告訴a,你調用我的邏輯,确實成功了。其實這個邏輯,非常類似tcp協定中的三次握手。上圖中的b流程。

6、類似double check機制的确認機制

    還是上圖中異步回調的過程,a在同步調用b,b傳回成功了。這次調用結束了,但是a為了確定,在過一段時間,這個時間可以是幾秒,也可以是每天定時處理,再調用b一次,查詢一下之前的那次調用是否成功。例如a調用b更新訂單狀态,這時候成功了,延遲幾秒後,a查詢b,确認一下狀态是否是自己剛剛期望的。上圖中的d流程。

三、分布式事務的缺點

1、二階段送出協定缺點

    兩階段送出涉及到多個節點的網絡通信,通信時間如果過長,事務的相對時間也就會過長,那麼鎖定資源的時間也就長了.在高并發的服務中,就會存在嚴重的性能瓶勁

 2、消息隊列

   在高并發的環境中,我們一般會采用消息隊列來避免分布式事務的執行。

   在使用消息隊列時,我們需要做到可靠憑證的儲存(分布式事務的消息),有如下幾種方式:

   以支付寶和餘額寶為例進行說明.

   支付寶完成扣錢的動作時,記錄消息資料,将消息資料和業務資料存在同一個資料庫執行個體中.

将支付寶完成扣錢的消息及時發送給餘額寶,餘額寶完成處理後傳回成功消息,支付寶收到消息後,消除消息表中對應的消息記錄,即完成本次扣錢操作.

分布式事務最終一緻性常用方案

傳統方式是,我做完了,發你消息。解決一緻性的方案的意思就是,我先發你消息,我做完了再跟你确認我做完了。這是改進後的有事務的消息中間件。