1. 程式人生 > >事務與兩階段提交

事務與兩階段提交

事務

事務是保證資料庫從一個一致性的狀態永久性地變成另一個一致性狀態的根基

ACID

ACID是事務基本特性:
A是Atomicity,原子性。一個事務往往涉及到許多的子操作,原子性則保證這些子操作要麼都做,要麼都不做,不能出現部分操作成功,而另外一部分操作失敗情形,基於此原則,如果事務在執行的中發生異常,那麼資料庫將回滾到事務發生之前的狀態。
C是Consistency,一致性。一致性是指事務發生前和發生後,都不會破壞原有的約束關係,保證了資料庫元素的正確性、有效性和完整性,其中的約束關係可以是資料庫內部的約束,比如資料庫元素的值必須在一定的範圍內,也可以是應用帶來的約束,比如銀行賬戶的餘額不能為負數。
I是Isolation,隔離性。一個事務的操作在提交之前,是不會被並行發生的其他事務訪問到的,也就是說,資料庫操作不會看到某個事務的中間操作結果,比如轉賬過程中,使用者是不能查詢到一個賬戶餘額減少了,而另外一個賬戶餘額未發生變化的情況。
D是Durability,永續性。事務完成以後,它對資料庫的影響是永久性的,即使在資料庫系統發生宕機或者其他故障的情況下,這種影響也會得到保持。

兩階段提交

兩階段提交機制是分散式事務實現的關鍵,在分散式系統中,事務往往包含有多個參與者,單個參與者上的事務能夠保證自身的ACID,而多個參與者之間的事務ACID則需要兩階段提交機制來保證,許多分散式關係型資料管理系統採用此機制來完成分散式事務。

兩階段提交機制依賴兩階段提交協議(two phase commit protocol,2PC),兩階段提交協議通過協調事務的參與者,決定提交或取消(回滾)事務,它能夠解決很多的臨時性系統故障(包括程序、網路節點、通訊等故障)問題,被廣泛地使用,它解決臨時性系統故障是通過使用日誌來記錄協議的狀態,從而使節點在故障恢復後可以繼續進行交易。兩階段提交協議並不能夠解決所有的故障,在某些情況下它還需要人為的參與才能解決問題。

在兩階段提交協議中,系統一般包含兩類節點:一類為協調者,通常一個系統中只有一個;另一類為事務參與者,一般包含多個,協議中假設每個節點都會記錄寫前日誌
(write-ahead log)並永續性儲存,這樣,即使節點發生故障日誌也不會丟失,協議中也假設節點不會發生永久性故障而且任意兩個節點都可以互相通訊


兩階段提交,顧名思義,由兩個階段組成:

階段1:請求階段(commit-request phase,或稱表決階段,voting phase)

在這個階段,協調者在自身節點的日誌中寫入一條的日誌記錄,然後所有參與者傳送訊息prepare T,詢問這些參與者是否能夠提交這個事務;
參與者在接受到這個prepare T 訊息以後,會根據自身的情況,進行事務的預處理,
如果參與者能夠提交該事務,則會將日誌寫入磁碟,並返回給協調者一個ready T資訊,同時自身進入預提交狀態狀態;

如果不能提交該事務,則記錄日誌,並返回一個not commit T資訊給協調者,同時撤銷在自身上所做的資料庫改;

參與者可以推遲傳送響應的時間,但最終還是需要傳送的。


階段2:提交階段(commit phase)

在這個階段,協調者會收集所有參與者的意見,
如果收到有參與者發來not commit T資訊,則標識著該事務不能提交,協調者會將Abort T 記錄到日誌中,並向所有參與者傳送一個Abort T 資訊,讓所有參與者撤銷在自身上所有的預操作;
如果協調者收到所有參與者發來ready T資訊,那麼協調者會將Commit T日誌寫入磁碟,並向所有參與者傳送一個Commit T資訊,提交該事務。
若協調者遲遲未收到某個參與者發來的資訊,則認為該參與者傳送了一個VOTE_ABORT資訊,從而取消該事務的執行。
如果參與者接收到協調者發來的Abort T資訊以後,將Abort T 記錄到日誌中,會終止提交;
如果參與者收到的是Commit T資訊,則寫入記錄,將事務進行提交。

兩階段提交機制圖示:


一般情況下,兩階段提交機制都能較好的執行,當在事務進行過程中,有參與者宕機時,他重啟以後,可以通過詢問其他參與者或者協調者,從而知道這個事務到底提交了沒有,當然,這一切的前提都是各個參與者在進行每一步操作時,都會事先寫入日誌。
兩階段提交存在的不能解決的困境:當協調者在發出commit T訊息後宕機了,而唯一收到這條命令的一個參與者也宕機了,這個時候這個事務就處於一個未知的狀態,沒有人知道這個事務到底是提交了還是未提交,從而需要資料庫管理員的介入,防止資料庫進入一個不一致的狀態。
當然,如果基於前面的假設即所有節點或者網路的異常最終都會恢復,那麼這個問題就不存在了,協調者和參與者最終會重啟,其他節點也最終也會收到commit T的資訊,這就是基於日誌完成的最終一致性

缺陷

兩階段提交協議最大的劣勢是其依賴“阻塞”完成,在節點等待訊息的時候處於阻塞狀態,節點中其他程序則需要等待阻塞程序釋放資源才能使用。另外,兩階段提交協議沒有容錯機制,一個節點發生故障整個事務都要回滾,代價比較大,這需要我們通過其它手段來完成容錯。

一個例子

一個例子來說明兩階段提交協議的工作過程:
A組織B、C和D三個人去爬長城,如果所有人都同意去爬長城,那麼活動將舉行,如果有一人不同意去爬長城,那麼活動將取消。
用2PC演算法解決該問題的過程如下:
角色劃分:A是活動的協調者,B、C和D是活動的參與者。

階段1:
A發郵件給B、C和D,提出下週三去爬山,問是否同意。此時A需要等待B、C和D的回覆郵件。
B、C收到郵件後發現自己在當日沒有活動安排,則發郵件告訴A他們同意下週三去爬長城。由於某種原因,D白天沒有檢視郵件,此時A、B和C均需要等待。到晚上的時候,D發現了A的郵件,然後檢視日程安排,發現週三當天已經有別的安排,那麼D回覆A說我去不了,至此第一階段的回覆完成。

階段2:
此時A收到了所有活動參與者的郵件,如果A發現三人都同意,則發下一封郵件通知三人說,活動確定了,下週三去爬山,事務完成,結束。
可是A發現D下週三不能去爬山,那麼A將發郵件通知B、C和D,下週三爬長城活動取消,

此時B、C回覆A“太可惜了”,D回覆A“不好意思”,至此該事務回滾,結束。

上面的例子中,A一共經歷了兩次傳送郵件並接受全部回覆的過程,這就是兩階段提交名字的由來。

通過該例子可以發現,2PC協議存在的缺陷。假如D不回覆郵件,那麼A、B和C將不得不處於等待的狀態。並且B和C所持有的資源,即下週三不能安排其它活動,一直不能釋放,其它等待該資源釋放的活動也將不得不處於等待狀態。

鑑於此問題,後來引入超時的機制,在超時發生以前,系統處於不確定階段;在超時發生以後,系統則轉入確定階段。

兩階段提交協議包含協調者和參與者,且二者都有發生問題的可能性。

假如協調者發生問題,我們可以選出另一個協調者來提交事務,例如,班長組織活動,如果班長生病了,我們可以請副班長來組織,這樣協調者出問題,那麼事務將不會取消或超時,如果班級活動希望每個人都能去,假如有一位同學不能去了,那麼直接取消活動即可,或者,如果大多數人去的話那麼活動如期舉行(2PC變種),

為了能夠更好地解決實際的問題,2PC協議存在很多的變種,例如:樹形2PC協議(或稱遞迴2PC協議)、動態2階段提交協議(D2PC)等。

參考:

http://www.blogjava.net/freeman1984/archive/2011/10/09/360269.html

http://blog.csdn.net/shenlan211314/article/details/7283948