分佈式事務:兩階段提交與三階段提交

在分佈式系統中著有 CAP 理論,該理論由加州大學伯克利分校的 Eric Brewer 教授提出,闡述了在一個分佈式系統中不可能同時知足 一致性(Consistency)可用性(Availability) ,以及 分區容錯性(Partition tolerance)數據庫

  • C:一致性

在分佈式系統中數據每每存在多個副本,一致性描述的是這些副本中的數據在內容和組織上的一致。服務器

  • A:可用性

可用性描述了系統對用戶的服務能力,所謂可用是指在用戶容忍的時間範圍內返回用戶指望的結果。網絡

  • P:分區容錯性

分佈式系統一般由多個節點構成,因爲網絡是不可靠的,因此存在分佈式集羣中的節點由於網絡通訊故障致使被孤立成一個個小集羣的可能性,即網絡分區,分區容錯性要求在出現網絡分區時系統仍然可以對外提供一致性的可用服務。分佈式

對於一個分佈式系統而言,咱們要始終假設網絡是不可靠的,所以分區容錯性是對一個分佈式系統最基本的要求,咱們的切入點更多的是嘗試在可用性和一致性之間尋找一個平衡點,但這也並不是要求咱們在系統設計時一直創建在網絡出現分區的前提之上,而後對一致性和可用性在選擇時非此即彼。性能

Eric Brewer 在 2012 年就曾指出 CAP 理論證實不能同時知足一致性、可用性,以及分區容錯性的觀點在實際系統設計指導上存在必定的誤導性 。傳統對於 CAP 理論的理解認爲在設計分佈式系統時必須知足 P,而後在 C 和 A 之間進行取捨,這是片面的,實際中網絡出現分區的可能性仍是比較小的,尤爲是目前網絡環境正在變得愈來愈好,甚至許多系統都擁有專線的支撐,因此在網絡未出現分區時,仍是應該兼顧 A 和 C;另外就是對於一致性、可用性,以及分區容錯性三者在度量上也應該有一個評定範圍,最簡單的以可用性來講,當有多少佔比請求出現響應超時才能夠被認爲是不知足可用性,而不是一出現超時就認爲是不可用的;最後咱們須要考慮的一點就是分佈式系統通常都是一個比較大且複雜的系統,咱們應該從更小的粒度上對各個子系統進行評估和設計,而不是簡單的從總體上武斷決策。spa

讓分佈式集羣始終對外提供可用的一致性服務一直是富有挑戰和趣味的一項任務。暫且拋開可用性,拿一致性來講,對於關係型數據庫咱們一般利用事務來保證數據的強一致性,當咱們的數據量愈來愈大,大到單庫已經沒法承擔時,咱們不得不採起分庫分表的策略對數據庫實現水平拆分,構建分佈式數據庫集羣,這樣能夠將一個數據庫的壓力分攤到多個數據庫,極大的提高了數據庫的存儲和響應能力,可是拆分以後也爲咱們使用數據庫帶來了許多的限制,好比主鍵的全局惟1、聯表查詢、數據聚合等等,另一個至關棘手的問題就是數據庫的事務由原先的單庫事務變成了如今的分佈式事務。設計

分佈式事務的實現並非無解的,好比下文要展開的兩階段提交(2PC:Two-Phrase Commit)和三階段提交(3PC:Three-Phrase Commit)都給咱們提供了思路,可是如何保證數據的強一致性,並對外提供高可用的服務仍是至關棘手的,所以不少分佈式系統對於數據強一致性都敬而遠之。日誌

兩階段提交協議(2PC:Two-Phrase Commit)

兩階段提交協議的目標在於在分佈式系統中保證數據的一致性,許多分佈式系統採用該協議提供對分佈式事務的支持。顧名思義,該協議將一個分佈式的事務過程拆分紅兩個階段: 投票階段事務提交階段 。爲了讓整個數據庫集羣可以正常的運行,該協議指定了一個「協調者」單點,用於協調整個數據庫集羣的運行,爲了簡化描述,咱們將數據庫裏面的各個節點稱爲「參與者」,三階段提交協議中一樣包含「協調者」和「參與者」這兩個定義。blog

第一階段:投票階段

該階段的主要目的在於打探數據庫集羣中的各個參與者是否可以正常的執行事務,具體步驟以下:事務

  1. 協調者向全部的參與者發送事務執行請求,並等待參與者反饋事務執行結果。
  2. 事務參與者收到請求以後,執行事務但不提交,並記錄事務日誌。
  3. 參與者將本身事務執行狀況反饋給協調者,同時阻塞等待協調者的後續指令。

第二階段:事務提交階段

在通過第一階段協調者的詢盤以後,各個參與者會回覆本身事務的執行狀況,這時候存在三種可能性:

  1. 全部的參與者都回復可以正常執行事務
  2. 一個或多個參與者回覆事務執行失敗
  3. 協調者等待超時

對於第一種狀況,協調者將向全部的參與者發出提交事務的通知,具體步驟以下:

  1. 協調者向各個參與者發送 commit 通知,請求提交事務。
  2. 參與者收到事務提交通知以後,執行 commit 操做,而後釋放佔有的資源。
  3. 參與者向協調者返回事務 commit 結果信息。

2pc-success

對於第2、三種狀況,協調者均認爲參與者沒法成功執行事務,爲了整個集羣數據的一致性,因此要向各個參與者發送事務回滾通知,具體步驟以下:

  1. 協調者向各個參與者發送事務 rollback 通知,請求回滾事務。
  2. 參與者收到事務回滾通知以後,執行 rollback 操做,而後釋放佔有的資源。
  3. 參與者向協調者返回事務 rollback 結果信息。

2pc-failed

兩階段提交協議解決的是分佈式數據庫數據強一致性問題,實際應用中更多的是用來解決事務操做的原子性,下圖描繪了協調者與參與者的狀態轉換。站在協調者的角度,在發起投票以後就進入了 WAIT 狀態,等待全部參與者回覆各自事務執行狀態,並在收到全部參與者的回覆後決策下一步是發送 commit 或 rollback 信息。站在參與者的角度,當回覆完協調者的投票請求以後便進入 READY 狀態(可以正常執行事務),接下去就是等待協調者最終的決策通知,一旦收到通知即可依據決策執行 commit 或 rollback 操做。

2pc-state

兩階段提交協議原理簡單、易於實現,可是缺點也是顯而易見的,主要缺點以下:

  • 單點問題

協調者在整個兩階段提交過程當中扮演着舉足輕重的做用,一旦協調者所在服務器宕機,就會影響整個數據庫集羣的正常運行,好比在第二階段中,若是協調者由於故障不能正常發送事務提交或回滾通知,那麼參與者們將一直處於阻塞狀態,整個數據庫集羣將沒法提供服務。

  • 同步阻塞

兩階段提交執行過程當中,全部的參與者都須要遵從協調者的統一調度,期間處於阻塞狀態而不能從事其餘操做,這樣效率極其低下。

  • 數據不一致性

兩階段提交協議雖然是分佈式數據強一致性所設計,但仍然存在數據不一致性的可能性,好比在第二階段中,假設協調者發出了事務 commit 通知,可是由於網絡問題該通知僅被一部分參與者所收到並執行了commit 操做,其他的參與者則由於沒有收到通知一直處於阻塞狀態,這時候就產生了數據的不一致性。

針對上述問題能夠引入 超時機制互詢機制 在很大程度上予以解決。對於協調者來講若是在指定時間內沒有收到全部參與者的應答,則能夠自動退出 WAIT 狀態,並向全部參與者發送 rollback 通知。對於參與者來講若是位於 READY 狀態,可是在指定時間內沒有收到協調者的第二階段通知,則不能武斷地執行 rollback 操做,由於協調者可能發送的是 commit 通知,這個時候執行 rollback 就會致使數據不一致。此時,咱們能夠介入互詢機制,讓參與者 A 去詢問其餘參與者 B 的執行狀況,若是 B 執行了 rollback 或 commit 操做,則 A 能夠大膽的與 B 執行相同的操做;若是 B 此時尚未到達 READY 狀態,則能夠推斷出協調者發出的確定是 rollback 通知;若是 B 一樣位於 READY 狀態,則 A 能夠繼續詢問另外的參與者,只有當全部的參與者都位於 READY 狀態時,此時兩階段提交協議沒法處理,將陷入長時間的阻塞狀態。

三階段提交協議(3PC:Three-Phrase Commit)

針對兩階段提交存在的問題,三階段提交協議經過引入一個 「預詢盤」 階段,以及超時策略來減小整個集羣的阻塞時間,提高系統性能。三階段提交的三個階段分別爲:can_commit,pre_commit,do_commit。

第一階段:can_commit

該階段協調者會去詢問各個參與者是否可以正常執行事務,參與者根據自身狀況回覆一個預估值,相對於真正的執行事務,這個過程是輕量的,具體步驟以下:

  1. 協調者向各個參與者發送事務詢問通知,詢問是否能夠執行事務操做,並等待回覆。
  2. 各個參與者依據自身情況回覆一個預估值,若是預估本身可以正常執行事務就返回肯定信息,並進入預備狀態,不然返回否認信息。

第二階段:pre_commit

本階段協調者會根據第一階段的詢盤結果採起相應操做,詢盤結果主要有三種:

  1. 全部的參與者都返回肯定信息
  2. 一個或多個參與者返回否認信息
  3. 協調者等待超時

針對第一種狀況,協調者會向全部參與者發送事務執行請求,具體步驟以下:

  1. 協調者向全部的事務參與者發送事務執行通知。
  2. 參與者收到通知後,執行事務但不提交。
  3. 參與者將事務執行狀況返回給客戶端。

在上述步驟中,若是參與者等待超時,則會中斷事務。 針對第2、三種狀況,協調者認爲事務沒法正常執行,因而向各個參與者發出 abort 通知,請求退出預備狀態,具體步驟以下:

  1. 協調者向全部事務參與者發送 abort 通知。
  2. 參與者收到通知後中斷事務。

3pc-fail-1

第三階段:do_commit

若是第二階段事務未中斷,那麼本階段協調者將會依據事務執行返回的結果來決定提交或回滾事務,分爲三種狀況:

  1. 全部的參與者都能正常執行事務
  2. 一個或多個參與者執行事務失敗
  3. 協調者等待超時

針對第一種狀況,協調者向各個參與者發起事務提交請求,具體步驟以下:

  1. 協調者向全部參與者發送事務 commit 通知。
  2. 全部參與者在收到通知以後執行 commit 操做,並釋放佔有的資源。
  3. 參與者向協調者反饋事務提交結果。

3pc-success

針對第2、三種狀況,協調者認爲事務沒法成功執行,因而向各個參與者發送事務回滾請求,具體步驟以下:

  1. 協調者向全部參與者發送事務 rollback 通知。
  2. 全部參與者在收到通知以後執行 rollback 操做,並釋放佔有的資源。
  3. 參與者向協調者反饋事務回滾結果。

3pc-fail-2

在本階段若是由於協調者或網絡問題,致使參與者遲遲不能收到來自協調者的 commit 或 rollback 請求,那麼參與者將不會如兩階段提交中那樣陷入阻塞,而是等待超時後繼續 commit,相對於兩階段提交雖然下降了同步阻塞,但仍然沒法徹底避免數據的不一致。

3pc-state

兩階段提交協議中所存在的長時間阻塞狀態發生的概率仍是很是低的,因此雖然三階段提交協議相對於兩階段提交協議對於數據強一致性更有保障,可是由於效率問題,兩階段提交協議在實際系統中反而更加受寵。在分佈式數據庫中,若是指望達到數據的強一致性,則服務基本沒有可用性可言,這也是爲何許多分佈式數據庫提供了跨庫事務,但也只是個擺設的緣由,在實際應用中咱們追求的更可能是數據的弱一致性。


鑑於做者水平有限,文中難免有錯誤之處,歡迎批評指正
我的博客:www.zhenchao.org

相關文章
相關標籤/搜索