在上一篇中,我們介紹了爲什麼使用分佈式,爲什麼會出現分佈式數據一致性問題,以及相關分佈式理論:CAP/BASE理論,這些是我們進行後邊介紹的分佈式一致性算法的基礎,正是由於在系統的可用性和數據一致性之間反覆的權衡,於是出現了一系列的一致性協議,如2PC,3PC,paxos算法等。本篇就介紹兩個最常見的分佈式一致性算法:兩階段提交(2PC),三階段提交(3PC)以及它們的相關應用。
其實我覺得這些分佈式一致性算法其實應該叫分佈式共識(distributed consensus)算法,不同的一致性上下文含義不同。共識系統則很清晰, 就是多個參與者針對某一個議題達成一致意見,如經典的具有高度容錯的基於消息傳遞的paxos算法,而2pc,3pc無法容錯,太過保守。而不是針對使副本數據都一致。這是我的一點看法,其實我看這個的概念的時候也很迷糊,到現在還是在頭腦中爭議很大,但我覺得,對於這些概念的理解應該放在固定的業務場景中,看在業務中解決了什麼問題,而不是轉牛角尖非要把這些算法分門別類。
另外,我自己的理解,這些分佈式一致性算法的目的並不是達到了副本數據的強一致性,因爲CAP理論告訴我們,這是不可能的,而是在可用性和一致性的均衡處理上,用這些算法可以達到BASE狀態,確保我們的分佈式系統正確運行,那些數據副本的同步問題並不是一致性算法所要解決的,因爲副本的同步不管是Mysql主從同步,還是其他master-slave集羣的同步都是異步的,所以不可能達到強一致性,所以這些一致性算法是用來保證分佈式系統的可用--一致的算法。例如,我們可以將paxos算法看做是分佈式共識算法,它的目的就是怎麼樣對某個值(決議)在集羣中達成一致,所以這可以用於集羣中的leader選舉,寫數據過程。而2pc,3pc就是解決分佈式事務(參與事務的事務管理器,參與者位於不同的節點)的原子性,一致性問題,而且這些算法並不是只能單一的應用於某個問題上,有很多問題都可以轉化爲用這些算法解決。
2PC、3PC的基本概念
2PC
- 協調者節點向所有參與者節點詢問是否可以執行提交操作(vote),並開始等待各參與者節點的響應。
- 參與者節點執行詢問發起爲止的所有事務操作,並將Undo信息和Redo信息寫入日誌。(注意:若成功這裏其實每個參與者已經執行了事務操作)
- 各參與者節點響應協調者節點發起的詢問。如果參與者節點的事務操作實際執行成功,則它返回一個”同意”消息;如果參與者節點的事務操作實際執行失敗,則它返回一個”中止”消息。
- 協調者節點向所有參與者節點發出”正式提交(commit)”的請求。
- 參與者節點正式完成操作,並釋放在整個事務期間內佔用的資源。
- 參與者節點向協調者節點發送”完成”消息。
- 協調者節點受到所有參與者節點反饋的”完成”消息後,完成事務。
- 協調者節點向所有參與者節點發出”回滾操作(rollback)”的請求。
- 參與者節點利用之前寫入的Undo信息執行回滾,並釋放在整個事務期間內佔用的資源。
- 參與者節點向協調者節點發送”回滾完成”消息。
- 協調者節點受到所有參與者節點反饋的”回滾完成”消息後,取消事務。
2PC的優缺點
- 1、同步阻塞問題。執行過程中,所有參與節點都是事務阻塞型的。當參與者佔有公共資源時,其他第三方節點訪問公共資源不得不處於阻塞狀態,各個參與者在等待協調者發出提交或中斷請求時,會一直阻塞,而協調者的發出時間要依賴於所有參與者的響應時間,如果協調者宕機了(單點),那麼他就一直阻塞在這,而且無法達成一致(3PC引入了超時提交解決)。
- 2、單點故障。由於協調者的重要性,一旦協調者發生故障。參與者會一直阻塞下去。尤其在第二階段,協調者發生故障,那麼所有的參與者還都處於鎖定事務資源的狀態中,而無法繼續完成事務操作。(如果是協調者掛掉,可以重新選舉一個協調者,但是無法解決因爲協調者宕機導致的參與者處於阻塞狀態的問題)
- 3、數據不一致。出現分區,或者網絡故障。在二階段提交的階段二中,當協調者向參與者發送commit請求之後,發生了局部網絡異常或者在發送commit請求過程中協調者發生了故障,這回導致只有一部分參與者接受到了commit請求。而在這部分參與者接到commit請求之後就會執行commit操作。但是其他部分未接到commit請求的機器則無法執行事務提交。於是整個分佈式系統便出現了數據部一致性的現象。
- 4、太過保守:2pc沒有設計相應的容錯機制,當任意一個參與者節點宕機,那麼協調者超時沒收到響應,就會導致整個事務回滾失敗。
- 5、二階段無法解決的問題:協調者(在第二階段)發出commit消息之後宕機,而唯一接收到這條消息的參與者同時也宕機了。那麼即使協調者通過選舉協議產生了新的協調者,這條事務的狀態也是不確定的,沒人知道事務是否被已經提交。
3PC
與兩階段提交不同的是,三階段提交有兩個改動點。
1、引入超時機制。(超時提交策略,當第三階段參與者等待協調者超時後會提交事務,解決參與者同步阻塞問題,同時能在發生單點故障時,繼續達成一致)
2、在第一階段和第二階段中插入一個準備階段。(也是爲了減少同步阻塞的發生範圍)
CanCommit階段
3PC的CanCommit階段其實和2PC的準備階段很像。協調者向參與者發送commit請求,參與者如果可以提交就返回Yes響應,否則返回No響應。
- 1.事務詢問 協調者向參與者發送CanCommit請求。詢問是否可以執行事務提交操作。然後開始等待參與者的響應。
- 2.響應反饋 參與者接到CanCommit請求之後,正常情況下,如果其自身認爲可以順利執行事務,則返回Yes響應,並進入預備狀態。否則反饋No
PreCommit階段
協調者根據參與者的反應情況來決定是否可以記性事務的PreCommit操作。根據響應情況,有以下兩種可能。
假如協調者從所有的參與者獲得的反饋都是Yes響應,那麼就會執行事務的預執行。
- 1.發送預提交請求 協調者向參與者發送PreCommit請求,並進入Prepared階段。
- 2.事務預提交 參與者接收到PreCommit請求後,會執行事務操作,並將undo和redo信息記錄到事務日誌中。
- 3.響應反饋 如果參與者成功的執行了事務操作,則返回ACK響應,同時開始等待最終指令。
- 1.發送中斷請求 協調者向所有參與者發送abort請求。
- 2.中斷事務 參與者收到來自協調者的abort請求之後(或超時之後,仍未收到協調者的請求),執行事務的中斷。
doCommit階段
該階段進行真正的事務提交,也可以分爲以下兩種情況。
執行提交
1.發送提交請求 協調接收到參與者發送的ACK響應,那麼他將從預提交狀態進入到提交狀態。並向所有參與者發送doCommit請求。
2.事務提交 參與者接收到doCommit請求之後,執行正式的事務提交。並在完成事務提交之後釋放所有事務資源。
3.響應反饋 事務提交完之後,向協調者發送Ack響應。
4.完成事務 協調者接收到所有參與者的ack響應之後,完成事務。
中斷事務 協調者沒有接收到參與者發送的ACK響應(可能是接受者發送的不是ACK響應,也可能響應超時),那麼就會執行中斷事務。
1.發送中斷請求 協調者向所有參與者發送abort請求
2.事務回滾 參與者接收到abort請求之後,利用其在階段二記錄的undo信息來執行事務的回滾操作,並在完成回滾之後釋放所有的事務資源。
3.反饋結果 參與者完成事務回滾之後,向協調者發送ACK消息
4.中斷事務 協調者接收到參與者反饋的ACK消息之後,執行事務的中斷。
3PC解決的問題:
2PC,3PC的應用
MySQL的主從同步複製原理
(1) 數據分佈 (Data distribution )
(2) 負載平衡(load balancing)
(3) 備份(Backups)
(4) 高可用性和容錯行 High availability and failover
整體上來說,複製有3個步驟:
(1) master將改變記錄到二進制日誌(binary log)中(這些記錄叫做二進制日誌事件,binary log events);
(2) slave將master的binary log events拷貝到它的中繼日誌(relay log);
(3) slave重做中繼日誌中的事件,將改變反映它自己的數據。
下一步就是slave將master的binary log拷貝到它自己的中繼日誌。首先,slave開始一個工作線程——I/O線程。I/O線程在master上打開一個普通的連接,然後開始binlog dump process。Binlog dump process從master的二進制日誌中讀取事件,如果已經跟上master,它會睡眠並等待master產生新的事件。I/O線程將這些事件寫入中 繼日誌。
SQL slave thread(SQL從線程)處理該過程的最後一步。SQL線程從中繼日誌讀取事件,並重放其中的事件而更新slave的數據,使其與master中的數 據一致。只要該線程與I/O線程保持一致,中繼日誌通常會位於OS的緩存中,所以中繼日誌的開銷很小。
此外,在master中也有一個工作線程:和其它MySQL的連接一樣,slave在master中打開一個連接也會使得master開始一個線程。複製 過程有一個很重要的限制——複製在slave上是串行化的,也就是說master上的並行更新操作不能在slave上並行操作。