在分佈式系統中,爲了保證數據的高可用,一般會將數據保留多個副本(replica),這些副本會放置在不一樣的物理的機器上。html
1.什麼是數據一致性git
在數據有多份副本的狀況下,若是網絡、服務器或者軟件出現故障,會致使部分副本寫入成功,部分副本寫入失敗。這就形成各個副本之間的數據不一致,數據內容衝突。github
形成事實上的數據不一致。算法
2.CAP定理數據庫
CAP理論認爲在分佈式的環境下設計和部署系統時,有3個核心的需求:服務器
Consistency,Availability和Partition Tolerance,即CAP。
Consistency:一致性,這個和數據庫ACID的一致性相似,但這裏關注的全部數據節點上的數據一致性和正確性,而數據庫的ACID關注的是在在一個事務內,對數據的一些約束。系統在執行過某項操做後仍然處於一致的狀態。在分佈式系統中,更新操做執行成功後全部的用戶都應該讀取到最新值。網絡
Availability:可用性,每個操做老是可以在必定時間內返回結果。須要注意「必定時間」和「返回結果」。「必定時間」是指,系統結果必須在給定時間內返回。「返回結果」是指系統返回操做成功或失敗的結果。架構
Partition Tolerance:分區容忍性,是否能夠對數據進行分區。這是考慮到性能和可伸縮性。分佈式
3.數據一致性模型微服務
一些分佈式系統經過複製數據來提升系統的可靠性和容錯性,而且將數據的不一樣的副本存放在不一樣的機器。
強一致性:
當更新操做完成以後,任何多個後續進程或者線程的訪問都會返回最新的更新過的值。這種是對用戶最友好的,就是用戶上一次寫什麼,下一次就保證能讀到什麼。根據 CAP 理論,這種實現須要犧牲可用性。
弱一致性:
系統並不保證續進程或者線程的訪問都會返回最新的更新過的值。用戶讀到某一操做對系統特定數據的更新須要一段時間,咱們稱這段時間爲「不一致性窗口」。系統在數據寫入成功以後,不承諾當即能夠讀到最新寫入的值,也不會具體的承諾多久以後能夠讀到。
最終一致性:
是弱一致性的一種特例。系統保證在沒有後續更新的前提下,系統最終返回上一次更新操做的值。在沒有故障發生的前提下,不一致窗口的時間主要受通訊延遲,系統負載和複製副本的個數影響。DNS 是一個典型的最終一致性系統。
跨行轉帳問題是一個典型的分佈式事務,用戶A向B的一個轉帳1000,要進行A的餘額-1000,B的餘額+1000,顯然必須保證這兩個操做的事務性。
相似的還有,電商系統中,當有用戶下單後,除了在訂單表插入記,還要在商品表更新庫存等,特別是隨着微服務架構的流行,分佈式事務的場景更變得更廣泛。
兩階段提交協議是協調全部分佈式原子事務參與者,並決定提交或取消(回滾)的分佈式算法。
1.協議參與者
在兩階段提交協議中,系統通常包含兩類機器(或節點):一類爲協調者(coordinator),一般一個系統中只有一個;另外一類爲事務參與者(participants,cohorts或workers),通常包含多個,在數據存儲系統中能夠理解爲數據副本的個數。協議中假設每一個節點都會記錄寫前日誌(write-ahead log)並持久性存儲,即便節點發生故障日誌也不會丟失。協議中同時假設節點不會發生永久性故障並且任意兩個節點均可以互相通訊。
2.兩個階段的執行
1.請求階段(commit-request phase,或稱表決階段,voting phase)
在請求階段,協調者將通知事務參與者準備提交或取消事務,而後進入表決過程。
在表決過程當中,參與者將告知協調者本身的決策:贊成(事務參與者本地做業執行成功)或取消(本地做業執行故障)。
2.提交階段(commit phase)
在該階段,協調者將基於第一個階段的投票結果進行決策:提交或取消。
當且僅當全部的參與者贊成提交事務協調者才通知全部的參與者提交事務,不然協調者將通知全部的參與者取消事務。
參與者在接收到協調者發來的消息後將執行響應的操做。
(3)兩階段提交的缺點
1.同步阻塞問題。執行過程當中,全部參與節點都是事務阻塞型的。
當參與者佔有公共資源時,其餘第三方節點訪問公共資源不得不處於阻塞狀態。
2.單點故障。因爲協調者的重要性,一旦協調者發生故障。
參與者會一直阻塞下去。尤爲在第二階段,協調者發生故障,那麼全部的參與者還都處於鎖定事務資源的狀態中,而沒法繼續完成事務操做。(若是是協調者掛掉,能夠從新選舉一個協調者,可是沒法解決由於協調者宕機致使的參與者處於阻塞狀態的問題)
3.數據不一致。在二階段提交的階段二中,當協調者向參與者發送commit請求以後,發生了局部網絡異常或者在發送commit請求過程當中協調者發生了故障,這回致使只有一部分參與者接受到了commit請求。
而在這部分參與者接到commit請求以後就會執行commit操做。可是其餘部分未接到commit請求的機器則沒法執行事務提交。因而整個分佈式系統便出現了數據部一致性的現象。
(4)兩階段提交沒法解決的問題
當協調者出錯,同時參與者也出錯時,兩階段沒法保證事務執行的完整性。
考慮協調者再發出commit消息以後宕機,而惟一接收到這條消息的參與者同時也宕機了。
那麼即便協調者經過選舉協議產生了新的協調者,這條事務的狀態也是不肯定的,沒人知道事務是否被已經提交。
三階段提交協議在協調者和參與者中都引入超時機制,而且把兩階段提交協議的第一個階段拆分紅了兩步:詢問,而後再鎖資源,最後真正提交。
(1)三個階段的執行
1.CanCommit階段
3PC的CanCommit階段其實和2PC的準備階段很像。
協調者向參與者發送commit請求,參與者若是能夠提交就返回Yes響應,不然返回No響應。
2.PreCommit階段
Coordinator根據Cohort的反應狀況來決定是否能夠繼續事務的PreCommit操做。
根據響應狀況,有如下兩種可能。
A.假如Coordinator從全部的Cohort得到的反饋都是Yes響應,那麼就會進行事務的預執行:
發送預提交請求。Coordinator向Cohort發送PreCommit請求,並進入Prepared階段。
事務預提交。Cohort接收到PreCommit請求後,會執行事務操做,並將undo和redo信息記錄到事務日誌中。
響應反饋。若是Cohort成功的執行了事務操做,則返回ACK響應,同時開始等待最終指令。
B.假若有任何一個Cohort向Coordinator發送了No響應,或者等待超時以後,Coordinator都沒有接到Cohort的響應,那麼就中斷事務:
發送中斷請求。Coordinator向全部Cohort發送abort請求。
中斷事務。Cohort收到來自Coordinator的abort請求以後(或超時以後,仍未收到Cohort的請求),執行事務的中斷。
3.DoCommit階段
該階段進行真正的事務提交,也能夠分爲如下兩種狀況:
執行提交
A.發送提交請求。Coordinator接收到Cohort發送的ACK響應,那麼他將從預提交狀態進入到提交狀態。並向全部Cohort發送doCommit請求。
B.事務提交。Cohort接收到doCommit請求以後,執行正式的事務提交。並在完成事務提交以後釋放全部事務資源。
C.響應反饋。事務提交完以後,向Coordinator發送ACK響應。
D.完成事務。Coordinator接收到全部Cohort的ACK響應以後,完成事務。
中斷事務
Coordinator沒有接收到Cohort發送的ACK響應(多是接受者發送的不是ACK響應,也可能響應超時),那麼就會執行中斷事務。
(2)三階段提交協議和兩階段提交協議的不一樣
對於協調者(Coordinator)和參與者(Cohort)都設置了超時機制(在2PC中,只有協調者擁有超時機制,即若是在必定時間內沒有收到cohort的消息則默認失敗)。
在2PC的準備階段和提交階段之間,插入預提交階段,使3PC擁有CanCommit、PreCommit、DoCommit三個階段。
PreCommit是一個緩衝,保證了在最後提交階段以前各參與節點的狀態是一致的。
(2)三階段提交協議的缺點
若是進入PreCommit後,Coordinator發出的是abort請求,假設只有一個Cohort收到並進行了abort操做,
而其餘對於系統狀態未知的Cohort會根據3PC選擇繼續Commit,此時系統狀態發生不一致性。
參考資料: