天天看點

分布式事務——三階段送出

在前文,我們介紹來了分布式事務,以及分布式事務的解決方案之一的 二階段送出

本文介紹分布式事務處理方案之一的三階段送出協定。

分布式事務

分布式事務是指發生在多個資料節點之間的事務,分布式事務比單機事務要複雜的多。在分布式系統中,各個節點之間在是互相獨立的,需要通過網絡進行溝通和協調。由于存在事務機制,可以保證每個獨立節點上的資料操作可以滿足ACID。但是,互相獨立的節點之間無法準确地知道其他節點的事務執行情況。是以從理論上來講,兩個節點的資料是無法達到一緻的狀态。如果想讓分布式部署的多個節點中的資料保持一緻性,那麼就要保證在所有節點資料的寫操作,要麼全部都執行,要麼全部都不執行。但是,一台機器在執行本地事務的時候無法知道其他機器中的本地事務的執行結果,是以它也就不知道本次事務到底應該commit還是rollback。是以,正常的解決辦法就是引入一個"協調者"的元件來統一排程所有分布式節點的執行。

為了解決這種分布式一緻性問題,前人在性能和資料一緻性的反反複複權衡過程中總結了許多典型的協定和算法。其中比較著名的有二階送出協定(Two Phase Commitment Protocol)、三階送出協定(Three Phase Commitment Protocol)和Paxos算法。針對分布式事務,是X/Open 這個組織定義的一套分布式事務的标準X/Open DTP(X/Open Distributed Transaction Processing ReferenceModel),定義了規範和API接口,可以由各個廠商進行具體的實作。

大部分的關系型資料庫通過兩階段送出(Two Phase Commit,2PC)算法來完成分布式事務,比如Oracle中通過dblink方式進行事務處理。下面重點介紹下3PC算法。

下面重點介紹下三階送出協定算法。

三階段送出概述

三階段送出協定可以了解為兩階段送出協定的改良版,是在協調者和參與者中都引入逾時機制,并且把兩階段送出協定的第一個階段分成了兩步: 詢問,然後再鎖資源,最後真正送出。

兩階段送出協定最早是分布式事務的專家Jim Gray在1978年的一篇文章Notes on Database Operating Systems中提及。兩階段送出協定可以保證資料的強一緻性,即保證了分布式事務的原子性:所有結點要麼全做要麼全不做。許多分布式關系型資料管理系統采用此協定來完成分布式事務。它是協調所有分布式原子事務參與者,并決定送出或取消(復原)的分布式算法。同時也是解決一緻性問題的算法。該算法能夠解決很多的臨時性系統故障(包括程序、網絡節點、通信等故障),被廣泛地使用。但是,它并不能夠通過配置來解決所有的故障,在某些情況下它還需要人為的參與才能解決問題。兩階段送出協定存在的問題是,協調者在某些時刻如果失敗了, 整個事務就會阻塞。于是Skeen釋出了"NonBlocking Commit Protocols" (1981)這篇論文,論文指出在一個分布式的事務裡面, 需要一個三階段的送出協定來避免在兩階段送出中存在的阻塞問題。

顧名思義,三階段送出分為以下三個階段:

  • CanCommit
  • PreCommit
  • DoCommit

在三階段送出協定中,系統一般包含兩類角色:

  • 協調者(Coordinator),通常一個系統中隻有一個;
  • 參與者(Participant),一般包含多個,在資料存儲系統中可以了解為資料副本的個數。

在CanCommit階段,協調者協定流程如下:

  • 寫本地日志“BEGIN_COMMIT”,并進入WAIT狀态;
  • 向所有參與者發送“VOTE_REQUEST”消息;
  • 等待并接收參與者發送的對“VOTE_REQUEST”的響應。參與者響應“VOTE_ABORT”或“VOTE_COMMIT”消息給協調者。

該流程與兩階段送出協定類似。

在PreCommit階段,,協調者将通知事務參與者準備送出或取消事務,寫本地的redo和undo日志,但不送出。

協調者協定流程如下:

  • 若收到任何一個參與者發送的“VOTE_ABORT”消息;
    • 寫本地“GLOBAL_ABORT”日志,進入ABORT狀态;
    • 向所有的參與者發送“GLOBAL_ABORT”消息;
  • 若收到所有參與者發送的“VOTE_COMMIT”消息;
    • 寫本地“PREPARE_COMMIT”日志,進入PRECOMMIT狀态;
    • 向所有的參與者發送“PREPARE _COMMIT”消息;
  • 等待并接收參與者發送的對“GLOBAL_ABORT”消息或“PREPARE_COMMIT”消息的确認響應消息。一旦收到所有參與者的“GLOBAL_ABORT”确認消息或者逾時沒有收到,寫本地“END_TRANSACTION”日志流程結束,則不再進入DoCommit階段。如果收到所有參與者的“PREPARE_COMMIT”确認消息,則進入DoCommit階段。

該流程與兩階段送出協定相比,多了一個PRECOMMIT狀态。

在該階段,

  • 向所有參與者發送的“GLOBAL _COMMIT”消息;
  • 等待并接收參與者發送的對 “GLOBAL_COMMIT”消息的确認響應消息,一旦收到所有參與者的确認消息,寫本地“END_TRANSACTION”日志流程結束。

在DoCommit階段,如果參與者無法及時接收到來自協調者的GLOBAL_COMMIT請求時,會在等待逾時之後,會繼續進行事務的送出。

三階段送出狀态機

下圖為三階段送出協定中的協調者及參與者的狀态機。左側a為協調者狀态機;右側b為參與者狀态機。

分布式事務——三階段送出

三階段送出的缺陷

相對于2PC,3PC主要解決的單點故障問題,并減少阻塞,因為一旦參與者無法及時收到來自協調者的資訊之後,他會預設執行commit。而不會一直持有事務資源并處于阻塞狀态。但是這種機制也會導緻資料一緻性問題,因為,由于網絡原因,協調者發送的abort響應沒有及時被參與者接收到,那麼參與者在等待逾時之後執行了commit操作。這樣就和其他接到abort指令并執行復原的參與者之間存在資料不一緻的情況。

參考引用

繼續閱讀