分佈式-分佈式事務

文章目錄


##一、分佈式事務- 二階段協議

###1.1 前言

在單個數據庫實例時候,我們可以在一個數據源的事務(本地事務)內做多步數據庫操作,在事務內的多個操作要麼全部執行生效,要麼全部不生效。在多數據實例節點時候,我們對多個實例的數據源進行操作時候就沒辦法把多個操作放到一個大的事務內來保證原子性了,因爲多個實例操作的是不同的數據源,而數據庫自帶的事務是針對單個數據源來說的。

所謂的兩個階段是指:

第一階段:準備階段(表決階段)和第二階段:提交階段(執行階段)。
準備階段:事務協調者(事務管理器)給每個參與者(資源管理器)發送Prepare消息,每個參與者要麼直接返回失敗(如權限驗證失敗),要麼在本地執行事務,寫本地的redo和undo日誌,但不提交,到達一種萬事俱備,只欠東風的狀態。
提交階段:如果協調者收到了參與者的失敗消息或者超時,直接給每個參與者發送回滾(Rollback)消息;否則,發送提交(Commit)消息;參與者根據協調者的指令執行提交或者回滾操作,釋放所有事務處理過程中使用的鎖資源。(注意:必須在最後階段釋放鎖資源)

###1.2 二階段協議

單個數據庫實例內的事務我們稱爲本地事務,需要保證多個數據源的操作要麼都做要麼都不做的事務我們成爲分佈式事務,爲了實現分佈式事務,二階段與三階段協議就應運而生了。

分佈式事務由事務發起者、資源管理器(參與者)、事務協調者組成,下面我們看看二階段協議內容:

####1.2.1 第一階段

分佈式事務發起方向事務協調器發起分佈式事務,協調器則向所有事務參與者發起準備請求,事務參與者接受到請求後執行本地事務,但是不提交。如果所有事務參與者都返回了準備OK到事務協調器

則事務協調器準備進入第二階段。如果有一個參與者返回準備失敗,則事務協調器向所有參與者發起事務回滾請求,事務參與者收到請求後回滾執行的本地事務,則分佈式事務結束。

####1.2.2 第二階段

事務協調器向所有事務參與者發起提交事務的請求,事務參與者接受到請求後,執行本地事務的提交操作。如果事務協調器收到所有參與者提交OK則分佈式事務結束。

###1.3 總結

二階段協議是個標準協議,協議只是規定了分佈式事務實現的骨架,並沒有規定具體如何實現,比如事務協調器是作爲一個單獨應用存在,還是與事務發起方一起部署的?事務參與者是單獨的應用還是與發起方一起的?並且並沒有考慮異常情況,比如第二階段如果有部分參與者返回提交失敗或者由於網絡原因返回了提交OK,但是事務協調器沒有收到,該怎麼處理?

另外分佈式事務並不是簡單說對多個數據源操作的原子性,還可以是數據源操作與遠程RPC的原子性,數據源與發送消息的原子性。

##二、分佈式事務- 三階段協議

###2.1 前言
前面我們介紹了爲解決分佈式事務而提出來的的二階段協議,本文首先來講解二階段的不足,然後闡述三階段協議,三階段協議也是一個標準的協議,也並沒有說具體如何實現。

###2.2 二階段協議存在的問題

  • 主要是同步阻塞問題
    在二階段的第一階段所有參與者接受到事務協調器的事務準備請求後,會在本地開啓並執行事務,但是沒有提交事務。所有參與者等待第二階段事務協調器發出事務提交或者回滾後纔會提交或者回滾事務。而在這期間所有參與者開啓的本地事務一直存在,也就是一直把相應的資源鎖定了(比如本地事務要更新一行數據,則在開啓事務後,事務提交或者回滾之前都一直通過行鎖鎖定了這行數據),導致其他需要訪問這行數據的事務阻塞等待。

假如在第一階段事務協調器給10個參與者發送準備請求,其中9個參與者正確接受了,並開啓了本地事務鎖定了具體的資源,而剩下一個參與者或者由於網絡問題沒有收到準備請求,或者接受到了但是本事事務執行失敗,或者執行正常,但是給事務協調器的回執由於網絡原因沒有被協調器收到等,則事務協調器發現其中一個參與者返回準備失敗或者等待超時後還沒收到那一個參與者的回執則會通知所有的參與者執行回滾操作。也就是在具體回滾前,其他9個參與者白白的鎖定了本地資源,成功的阻止了在開啓事務和回滾之前其他事務訪問鎖定的資源,這顯然很浪費。

###2.3 三階段協議

三階段協議把二階段的第一階段在細分爲2階段,具體內容如下:

####2.3.1 第一階段canCommit

事務發起方發起事務後,事務協調器會給所有的事務參與者發起canCommit?的請求,參與者收到後根據自己的情況判斷是否可以執行提交,如果可以則回執OK,否者返回fail,並不開啓本地事務並執行。具體參與者是如何判斷本地是否可以執行提交協議並沒有具體規定,需要協議實現者自己規定,比如可能判斷參與者是否存在(網絡是否OK)或者本地數據庫連接是否可用來判斷(YY)。
如果協調器發現有些發起方返回fail或者等待超時後參與者還沒返回則給所有事務參與者發起中斷操作,具體中斷操作做什麼協議也沒有具體規定。如果協調器發現所有參與者返回可以提交,則進入第二階段。

###2.3.1 第二階段preCommit

事務協調器向所有參與者發起準備事務請求,參與者接受到後,開啓本地事務並執行,但是不提交。剩下的與二階段的一階段一致。

####2.3.1 第三階段doCommit

與二階段中的二階段一致。

###2.4 總結

三階段與二階段最大不同在於三階段協議把二階段的第一階段拆分爲了兩個階段,其中第一階段並不鎖定資源,而是詢問參與者是否可以提交,等所有參與者回覆OK後在具體執行第二階段鎖定資源。理論上如果第一階段返回都OK,則第二階段和三階段執行成功的概率就很大,另外如果第一階段有些參與者返回了fail,由於這時候其他參與者還沒有鎖定資源,所以不會造成資源的阻塞。

##三、分佈式事務- TCC編程式模式

###3.1 前言

嚴格遵守ACID的分佈式事務我們稱爲剛性事務,而遵循BASE理論(基本可用:在故障出現時保證核心功能可用,軟狀態:允許中間狀態出現,最終一致性:不要求分佈式事務打成中時間點數據都是一致性的,但是保證達到某個時間點後,數據就處於了一致性了)的事務我們稱爲柔性事務,其中TCC編程模式就屬於柔性事務,本文我們來闡述其理論。

###3.2 TCC編程模式

  • TCC編程模式本質上也是一種二階段協議,不同在於TCC編程模式需要與具體業務耦合

###3.3 TCC編程模式步驟:

  • 所有事務參與方都需要實現try,confirm,cancle接口。

  • 事務發起方向事務協調器發起事務請求,事務協調器調用所有事務參與者的try方法完成資源的預留,這時候並沒有真正執行業務,而是爲後面具體要執行的業務預留資源,這裏完成了一階段。
    如果事務協調器發現有參與者的try方法預留資源時候發現資源不夠,則調用參與方的cancle方法回滾預留的資源,需要注意cancle方法需要實現業務冪等,因爲有可能調用失敗(比如網絡原因參與者接受到了請求,但是由於網絡原因事務協調器沒有接受到回執)會重試。

  • 如果事務協調器發現所有參與者的try方法返回都OK,則事務協調器調用所有參與者的confirm方法,不做資源檢查,直接進行

###3.4 具體的業務操作。

  • 如果協調器發現所有參與者的confirm方法都OK了,則分佈式事務結束。

  • 如果協調器發現有些參與者的confirm方法失敗了,或者由於網絡原因沒有收到回執,則協調器會進行重試。這裏如果重試一定次數後還是失敗,會怎麼樣那?常見的是做事務補償。

  • 螞蟻金服基於TCC實現了XTS(雲上叫DTS),目前在螞蟻金服雲上有對外輸出,這裏我們來結合其提供的一個例子來具體理解TCC的含義,以下引入螞蟻金服雲實例:

“首先我們假想這樣一種場景:轉賬服務,從銀行 A 某個賬戶轉 100 元錢到銀行 B 的某個賬戶,銀行 A 和銀行 B 可以認爲是兩個單獨的系統,也就是兩套單獨的數據庫。

我們將賬戶系統簡化成只有賬戶和餘額 2 個字段,並且爲了適應 DTS 的兩階段設計要求,業務上又增加了一個凍結金額(凍結金額是指在一筆轉賬期間,在一階段的時候使用該字段臨時存儲轉賬金額,該轉賬額度不能被使用,只有等這筆分佈式事務全部提交成功時,纔會真正的計入可用餘額)。按這樣的設計,用戶的可用餘額等於賬戶餘額減去凍結金額。這點是理解參與者設計的關鍵,也是 DTS 保證最終一致的業務約束。”

在try階段並沒有對銀行A和B數據庫中的餘額字段做操作,而是對凍結金額做的操作,對應A銀行預留資源操作是對凍結金額加上100元,這時候A銀行賬號上可用錢爲餘額字段-凍結金額;對應B銀行的操作是對凍結金額上減去100,這時候B銀行賬號上可用的錢爲餘額字段-凍結金額。

如果事務協調器調用銀行A和銀行B的try方法有一個失敗了(比如銀行A的賬戶餘額不夠了),則調用cancle進行回滾操作(具體是對凍結金額做反向操作)。如果調用try方法都OK了,則進入confirm階段,confirm階段則不做資源檢查,直接做業務操作,對應銀行A要在賬戶餘額減去100,然後凍金額減去100;對應銀行B要對賬戶餘額字段加上100,然後凍結金額加上100。

最關心的,如果confirm階段如果有一個參與者失敗了,該如何處理,其實上面操作都是xts-client做的,還有一個xts-server專門做事務補償的。

###3.5 總結

TCC是對二階段的一個改進,try階段通過預留資源的方式避免了同步阻塞資源的情況,但是TCC編程需要業務自己實現try,confirm,cancle方法,對業務入侵太大,實現起來也比較複雜。

###3.6 應用場景

###3.7 其他分佈式事務處理策略

####3.7.1 可靠消息最終一致性

####3.7.2 最大努力通知型

##四、CAP

  • CAP理論是由EricBrewer教授提出的,在設計和部署分佈式應用的時候,存在三個核心的系統需求

###4.1 C(Consistency)

  • 一致性是說數據的原子性,這種原子性在經典ACID的數據庫中是通過事務來保證的,當事務完成時,無論其是成功還是回滾,數據都會處於一致的狀態.
  • 在分佈式環境中,一致性是說多點的數據是否一致.

###4.2 A(Availability)

  • 可用性是說服務能一直保證是可用的狀態,當用戶發出一個請求,服務能在有限時間內返回結果。

  • 而這種可用性是不關乎結果的正確與否,所以,如果服務一致返回錯誤的數據,其實也可以稱爲其是可用的。

###4.3 P(Tolerance of network Partition)

  • 是指網絡的分區
  • 網絡中的兩個服務結點出現分區的原因很多,比如網絡斷了、對方結點因爲程序bug或死機等原因不能訪問

###4.4 CAP

  • 一個分佈式系統不可能滿足一致性,可用性和分區容錯性這三個需求,最多隻能同時滿足兩個。

原始證明:
Brewer’s CAP Theorem
http://www.julianbrowne.com/article/brewers-cap-theorem

我們也來推演證明一下?

  • CA 傳統數據庫
  • AP 大多數網站架構的選擇
  • CP Redis MongoDB

用戶對數據的不一致性是不敏感的(數字敏感的場景除外)

###4.5 BASE

BASE是AP組合的延伸

  • Basically Availble --基本可用

  • Soft-state --軟狀態/軟事務

  • Eventual Consistency --最終一致性

  • BASE模型犧牲高一致性,獲得可用性或可靠性: Basically Available基本可用

  • Soft state軟狀態 狀態可以有一段時間不同步,異步。

  • Eventually consistent最終一致,最終數據是一致的就可以了,而不是時時一致。

BASE思想主要強調基本的可用性,如果你需要高可用性,也就是純粹的高性能,那麼就要以一致性或容錯性爲犧牲,BASE思想的方案在性能上還是有潛力可挖的
ebay架構分享:http://www.infoq.com/cn/news/2008/03/ebaybase

##五、Eventual Consistency(最終一致性)

Amazon popularized the concept of “Eventual Consistency”. Their definition is: The storage system guarantees that if no new updates are made to the object, eventually all accesses will return the last updated value.

###5.1 典型場景

  • DNS
  • Single Write/multi read Mastaer/Slave
  • Web Cache

###5.2 強一致性(即時一致性)

  • 假如A先寫入了一個值到存儲系統,存儲系統保證後續A,B,C的讀取操作都將返回最新值

###5.3 弱一致性

  • 假如A先寫入了一個值到存儲系統,存儲系統不能保證後續A,B,C的讀取操作能讀取到最新值。此種情況下有一個“不一致性窗口”的概念,它特指從A寫入值,到後續操作A,B,C讀取到最新值這一段時間。

###5.4 最終一致性

  • 最終一致性是弱一致性的一種特例。假如A首先write了一個值到存儲系統,存儲系統保證如果在A,B,C後續讀取之前沒有其它寫操作更新同樣的值的話,最終所有的讀取操作都會讀取到最A寫入的最新值。

  • 如果沒有失敗發生的話,“不一致性窗口”的大小依賴於以下的幾個因素:

    • 交互延遲
    • 系統的負載
    • 以及複製技術中Replicate的個數(這個可以理解爲master/salve模式中,salve的個數)
發佈了105 篇原創文章 · 獲贊 63 · 訪問量 160萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章