# 分布式基礎之二階段提交
二階段提交(Two Phase Commit)在分布式事務處理中非常常見。它主要用來保證分布式事務處理的一致性,決定事務的提交或回滾。目前二階段提交廣泛應用于關系型數據庫的分布式事務處理中,它是分布式系統中的一個常見協議。
### 需求
為什么要二階段提交?因為在分布式系統中,每個節點只知道自己的事務是否執行成功了,而分布式系統要求一致性,也就是所有的節點的狀態都應該一致。如果某一個事務只在部分節點執行成功,那么勢必會導致各分布式節點不一致。二階段提交就是用來保證要么所有的節點都執行了該事務,要么都不執行。
### 簡介
顧名思義,二階段提交要通過兩個階段來完成。此外在二階段中主要分為兩種角色:協調節點與普通節點。而且協議中還假設節點不會發生永久性故障,而且任意兩個節點都可以互相通信。
### 提交階段
在提交階段,協調節點將事務分發給普通節點,普通節點進行事務的處理并返回響應。具體過程如下:
1. 協調節點向各普通節點發送事務內容,等待普通節點的回應
1. 各普通節點執行事務,并記錄下日志(用來事務中斷時進行回滾)
1. 各普通節點返回響應,判斷事務是否執行成功
> 注:協調節點需要設置超時時限,如果有普通節點在超時時限內都沒有響應,認為事務執行失敗。
### 執行階段
在執行階段,根據各普通節點的響應結果來進行事務的提交或回滾。
**執行事務**
1. 所有的普通節點都返回說事務執行成功
1. 協調者向所有的普通節點發送執行命令
1. 普通節點在收到執行命令后對事務結果進行提交,并釋放整個事務執行期間占用的資源
1. 提交完成后向協調節點發送回應消息(ack)
1. 協調節點接收到所有的回應消息后完成事務處理
**中斷事務**
1. 有普通節點執行事務失敗或者超時
1. 協調者向所有普通節點發送回滾請求
1. 普通節點根據日志執行回滾操作,并釋放在整個事務執行期間占用的資源
1. 回滾完成后向協調節點發送回應消息(ack)
1. 協調節點接收到所有的回應消息后完成事務中斷
下面是事務提交成功的說明圖:

下面是事務中斷的說明圖:

> 注:圖片來源于網絡
### 節點運行狀況
我們來分類討論一下各節點出現問題時會對二階段提交產生什么影響:
**協調節點正常,普通節點失效**:
如果普通節點在提交階段失效會導致因超時而中斷事務;如果在執行階段失效,那么會導致這個節點與其他的節點出現不一致現象。這時可以通過協調者對該節點進行事務的重新提交,或者該節點主動詢問協調者或其他節點進行同步。
**協調節點失效,普通節點正常**:
如果調節節點失效,那么會導致收到提交請求的普通節點占用了事務資源,并一直在等待調節節點作出反饋來決定是執行事務還是回滾。可以等待協調節點恢復或者設定一種備用協調節點機制。
**協調節點失效,普通節點失效**:
在這種情況下會出現一種非常危險的錯誤,如果協調節點在發出了部分執行命令后失效,且接收到該執行命令的節點后來也失效了,那么就無法知道整個分布式系統的最終決定要不要執行該事務操作。這時只能進行數據訂正或者等節點恢復正常后再進行相關操作。
### 優缺點
**優點**
二階段明顯的優點就是邏輯很簡單,易于在系統中實現。
**缺點**
就是因為二階段提交協議的簡單,也使得它存在一些缺陷:
單點問題:
顯然協調節點在整個協議中處在一個中心位置,一旦協調節點出現問題,那么整個二階段操作都會受到嚴重影響。
數據不一致:
也就是協調節點失效,普通節點失效的情況,這時候可能部分普通節點執行了事務,而部分普通節點沒有執行事務。
阻塞引起的性能問題:
由于在二階段提交中需要等到所有的節點都作出反應,需要花費大量的開銷在阻塞操作上,此時普通節點不能進行其他事物操作,性能會受到影響。