大型的分佈式系統架構都會涉及到事務的分佈式處理的問題,基原本說,分佈式事務和普通事務都有一個共同原則:數據庫
另一個設計原則,分佈式系統要符合如下原則:網絡
因爲在設計分佈式系統時,難以保證CAP所有符合,最多保證其中兩個,例如在一個分佈式系統中:
要保證系統數據庫的強一致性,須要跨表跨庫佔用數據庫資源,在複雜度比較高的狀況下,耗時難以保證,就會出現可用性沒法保證的狀況。架構
故而又出現了BASE理論異步
實際上BASE理論是基於AP的一個擴展,一個分佈式事務不須要強一致性,只須要達到一個最終一致性就能夠了。分佈式
分佈式事務就是處理分佈式中各個節點的數據操做,使之可以在節點相互隔離的狀況下完成多個節點數據的一致性操做。性能
2PC即二階段提交,在這裏須要瞭解兩個概念spa
準備階段中,協調者向參與者發送precommit的消息,參與者在本地執行事務邏輯,若是沒有超時以及運行無誤,那麼會記錄redo和undo日誌,將ack信息發送給協調者,當協調者收到全部節點參與者發送的ack信息時,準備進入下一階段,不然會發送回滾信息給各個節點,各個節點根據以前記錄好的undo信息回滾,本次事務提交失敗。設計
提交階段中,協調者已經收到全部節點的應答信息,接下來發送commit消息給各個節點,通知各個節點參與者能夠提交事務,各個參與者提交完畢後一一發送完成信息給協調者,並釋放本地佔用的資源,協調者收到全部完成消息後,完成事務。日誌
二階段提交的圖示以下:
中間件
二階段提交雖然可以解決大多數的分佈式事務的問題,且發生數據錯誤的機率極小,但仍然有如下幾個問題:
針對於以上提出的一些問題,衍生出了3PC。
3PC即三階段提交協議。
3PC相對於2PC,有了如下變化:
這是一個準備階段,在這一階段中,協調者向參與者發送CanCommit消息,參與者接收後,根據自身資源狀況判斷是否能夠執行事務操做,若是能夠而且未超時,則發送yes給協調者,反之,協調者會中斷事務。
這是預備階段,在這一階段中,協調者向參與者發送PreCommit消息,參與者接收後,會執行事務操做,記錄undo和redo日誌,事務執行完畢後會將Ack消息發送給協調者,協調者在未超時的狀況下收集全部參與者的信息,不然中斷事務,通知全部參與者Abort消息。
當全部參與者Ack消息完畢以後,協調者會確認發送DoCommit消息給每個參與者,執行提交事務。原則上全部參與者執行提交完畢以後,須要發送Committed給協調者,協調者完成事務。不然協調者中斷事務,參與者接收abort消息會根據以前記錄的undo回滾。
但也要注意,此階段中若是參與者沒法及時收到協調者發來的Docommit消息時,也會自行提交事務,由於從機率上來說,PreCommit這個階段可以不被abort說明所有節點均可以正常執行事務提交,因此通常來說單個節點提交不影響數據一致性,除非極端狀況。
相對於2PC,3PC主要解決的單點故障問題,並減小阻塞,由於一旦參與者沒法及時收到來自協調者的信息以後,他會默認執行commit。而不會一直持有事務資源並處於阻塞狀態。可是這種機制也會致使數據一致性問題,由於,因爲網絡緣由,協調者發送的abort響應沒有及時被參與者接收到,那麼參與者在等待超時以後執行了commit操做。這樣就和其餘接到abort命令並執行回滾的參與者之間存在數據不一致的狀況。
上面提到的關於協調者在實踐過程當中由誰來擔任是個問題,通常來說這個協調者是異步的,能夠在參與者和協調者之間雙向通訊的,有良好的消息傳遞機制,可以保證消息穩定投遞。故而通常協調者的擔任者是高性能的消息中間件例如RocketMq、Kafka、RabbitMq等。
如圖就是一個2PC的實踐: