目前的應用系統,不論是企業級應用仍是互聯網應用,最終數據的一致性是每一個應用系統都要面臨的問題,隨着分佈式的逐漸普及,數據一致性更加艱難,可是也很難有銀彈的解決方案,也並非引入特定的中間件或者特定的開源框架可以解決的,更多的仍是看業務場景,根據場景來給出解決方案。根據筆者最近幾年的瞭解,總結了幾個點,更多的應用系統在編碼的時候,更加關注數據的一致性,這樣系統纔是健壯的。java
1、基礎理論spring
目前關於事務的幾大理論包括:ACID事務特性,CAP分佈式理論,以及BASE等。ACID在數據庫事務中體現,CAP和BASE則是分佈式事務的理論,結合業務系統,例如訂單管理,例如倉儲管理等,能夠借鑑這些理論,從而解決問題。數據庫
一、ACID 特性網絡
二、CAP特性併發
三、BASE特性框架
2、最終一致性的經常使用作法異步
一、單數據庫事務分佈式
若是應用系統是單一的數據庫,那麼這個很好保證,利用數據庫的事務特性來知足事務的一致性,這時候的一致性是強一致性的。對於java應用系統來說,不多直接經過事務的start和commit以及rollback來硬編碼,大多經過spring的事務模板或者聲明式事務來保證;高併發
二、多數據庫事務性能
針對多數據庫事務能夠根據二階段提交協議,採用spring 3.0 + Atomikos + JTA進行支持;
三、基於事務型消息隊列的最終一致性
藉助消息隊列,在處理業務邏輯的地方發送消息,業務邏輯處理成功後,提交消息,確保消息是發送成功的,以後消息隊列投遞來進行處理,若是成功,則結束,若是沒有成功,則重試,直到成功,不過僅僅適用業務邏輯中,第一階段成功,第二階段必須成功的場景。對應上圖中的C流程。
四、基於消息隊列+定時補償機制的最終一致性
前面部分和上面基於事務型消息的隊列,不一樣的是,第二階段重試的地方,再也不是消息中間件自身的重試邏輯了,而是單獨的補償任務機制。其實在大多數的邏輯中,第二階段失敗的機率比較小,因此單獨獨立補償任務表出來,能夠更加清晰,可以比較明確的直到當前多少任務是失敗的。對應上圖的E流程。
五、異步回調機制的引入
A應用調用B,在同步調用的返回結果中,B返回成功給到A,通常狀況下,這時候就結束了,其實在99.99%的狀況是沒問題的,可是有時候爲了確保100%,記住最起碼在系統設計中100%,這時候B系統再回調A一下,告訴A,你調用個人邏輯,確實成功了。其實這個邏輯,很是相似TCP協議中的三次握手。上圖中的B流程。
六、相似double check機制的確認機制
仍是上圖中異步回調的過程,A在同步調用B,B返回成功了。此次調用結束了,可是A爲了確保,在過一段時間,這個時間能夠是幾秒,也能夠是天天定時處理,再調用B一次,查詢一下以前的那次調用是否成功。例如A調用B更新訂單狀態,這時候成功了,延遲幾秒後,A查詢B,確認一下狀態是不是本身剛剛指望的。上圖中的D流程。
3、分佈式事務的缺點
一、二階段提交協議缺點
兩階段提交涉及到多個節點的網絡通訊,通訊時間若是過長,事務的相對時間也就會過長,那麼鎖定資源的時間也就長了.在高併發的服務中,就會存在嚴重的性能瓶勁
二、消息隊列
在高併發的環境中,咱們通常會採用消息隊列來避免分佈式事務的執行。
在使用消息隊列時,咱們須要作到可靠憑證的保存(分佈式事務的消息),有以下幾種方式:
以支付寶和餘額寶爲例進行說明.
支付寶完成扣錢的動做時,記錄消息數據,將消息數據和業務數據存在同一個數據庫實例中.
Begin Transaction update A set amount=amount-1000 where uid=100; insert into message(uid,amount,status) values (1,1000,1) End Transaction Commit;
將支付寶完成扣錢的消息及時發送給餘額寶,餘額寶完成處理後返回成功消息,支付寶收到消息後,消除消息表中對應的消息記錄,即完成本次扣錢操做.
傳統方式是,我作完了,發你消息。解決一致性的方案的意思就是,我先發你消息,我作完了再跟你確認我作完了。這是改進後的有事務的消息中間件。