分佈式學習之一:事務

 

 

事務處理

讓咱們用最經典的 Use Case:「A賬號向B賬號匯錢」來講明一下,熟悉RDBMS事務的都知道從賬號A到賬號B須要6個操做:node

  1. 從A賬號中把餘額讀出來;
  2. 對A賬號作減法操做;
  3. 把結果寫回A賬號中;
  4. 從B賬號中把餘額讀出來;
  5. 對B賬號作加法操做;
  6. 把結果寫回B賬號中;

爲了數據的一致性,這6件事,要麼都成功作完,要麼都不成功,並且這個操做的過程當中,對A、B賬號的其它訪問必需鎖死,所謂鎖死就是要排除其它的讀寫操做,否則會有髒數據的問題,這就是事務mysql

若是A賬號和B賬號的數據不在同一臺服務器上怎麼辦?咱們須要一個跨機器的事務處理。也就是說,若是A的扣錢成功了,但B的加錢不成功,咱們還要把A的操做給回滾回去。這在跨機器的狀況下,就變得比較複雜了。算法

若是不考慮性能的話,保證事務並不困難,系統慢一點就好了;除了考慮性能外,咱們還要考慮可用性,也就是說,一臺機器沒了,數據不丟失,服務可由別的機器繼續提供。 因而,咱們須要重點考慮下面的這麼幾個狀況:sql

  • 容災:數據不丟、節點的Failover;
  • 數據的一致性:事務處理;
  • 性能:吞吐量 、 響應時間

 

要解決數據不丟,只能經過數據冗餘的方法,就算是數據分區,每一個區也須要進行數據冗餘處理。這就是數據副本:當出現某個節點的數據丟失時能夠從副本讀到,數據副本是分佈式系統解決數據丟失異常的惟一手段。因此在數據冗餘狀況下考慮數據的一致性和性能的問題:數據庫

1)要想讓數據有高可用性,就得寫多份數據。服務器

2)寫多份的問題會致使數據一致性的問題。網絡

3)數據一致性的問題又會引起性能問題併發

這就是軟件開發,按下了葫蘆起了瓢。異步

 

數據一致性能夠簡單分爲三類:分佈式

  1. 弱一致性(weak),當你寫入一個新值後,讀操做在數據副本上可能讀出來,也可能讀不出來。
  2. 強一致性(strong),新的數據一旦寫入,在任意副本任意時刻都能讀到新值。
  3. 最終一致性(eventually),當你寫入一個新值後,有可能讀不出來,但在某個時間窗口以後保證最終能讀出來。

 

 


 

2PC協議

在分佈式系統中,每一個節點雖然能夠知曉本身的操做時成功或者失敗,卻沒法知道其餘節點的操做的成功或失敗。當一個事務跨越多個節點時,引入一個做爲協調者(coordinator)的組件來統一掌控全部節點(稱做參與者)的操做結果,並最終指示這些節點是否要把操做結果進行真正的提交(好比將更新後的數據寫入磁盤等等)。

 

兩階段提交(two phase commit, 2PC)的算法以下:

第一階段(vote)

  1. 協調者問全部的參與者,是否能夠執行提交操做;
  2. 各個參與者開始事務執行的準備工做:如:爲資源上鎖,預留資源,寫undo/redo log;
  3. 參與者響應協調者,若是事務的準備工做成功,則迴應「能夠提交」,不然迴應「拒絕提交」;

第二階段(commit)

  1. 若是全部的參與者都回應「能夠提交」,那麼,協調者向全部的參與者發送「正式提交」的命令。參與者完成正式提交,並釋放全部資源,而後迴應「完成」,協調者收集各結點的「完成」迴應後結束這個Global Transaction;
  2. 若是有一個參與者迴應「拒絕提交」,那麼,協調者向全部的參與者發送「回滾操做」,並釋放全部資源,而後迴應「回滾完成」,協調者收集各結點的「回滾」迴應後,取消這個Global Transaction;

 

2PC實現了強一致性,其最大缺點就是它經過阻塞完成,會極大影響性能;另外一個問題則在timeout上:

  1. 第一階段中,若是參與者沒有收到詢問請求,或是參與者的迴應沒有到達協調者。那麼,須要協調者作超時處理,一旦超時,能夠看成失敗,也能夠重試。
  2. 第二階段中,正式提交發出後,若是有的參與者沒有收到,或是參與者提交/回滾後的確認信息沒有返回,一旦參與者的迴應超時,要麼重試,要麼把那個參與者標記爲問題結點剔除整個集羣,這樣能夠保證服務結點都是數據一致性的。
  3. 第二階段中,若是參與者收不到協調者的commit/fallback指令,參與者將處於「狀態未知」階段,參與者徹底不知道要怎麼辦,好比:若是全部的參與者完成第一階段的回覆後(可能所有yes,可能所有no,可能部分yes部分no),若是協調者在這個時候掛掉了。那麼全部的結點徹底不知道怎麼辦(問別的參與者都不行),這個狀態會block整個事務,爲此,引入了3PC的概念。

 

3PC協議

3PC是把二段提交的第一個段break成了兩段:詢問,而後再鎖資源。最後真正提交。其核心理念是:在詢問的時候並不鎖定資源,除非全部人都贊成了,纔開始鎖資源

 

理論上來講,若是第一階段全部的結點返回成功,那麼有理由相信成功提交的機率很大。這樣一來,能夠下降參與者Cohorts的狀態未知的機率。也就是說,一旦參與者收到了PreCommit,意味他知道你們其實都贊成修改了。這一點很重要。下面咱們來看一下3PC的狀態遷移圖:(注意圖中的虛線,那些F,T是Failuer或Timeout,其中的:狀態含義是 q – Query,a – Abort,w – Wait,p – PreCommit,c – Commit)

 

從上圖的狀態變化圖咱們能夠從虛線(那些F,T是Failuer或Timeout)看到——若是結點處在P狀態(PreCommit)的時候發生了F/T的問題,三段提交比兩段提交的好處是,三段提交能夠繼續直接把狀態變成C狀態(Commit),而兩段提交則不知所措

 

 

paxos算法

Paxos是一種民主選舉的算法,目的是讓整個集羣對某個值的變動達成一致,大多數節點的決定會成個整個集羣的決定。任何一個點均可以提出要修改某個數據的提案,是否經過這個提案取決於這個集羣中是否有超過半數的結點贊成(須要集羣中的節點是單數)。

這個算法有兩個階段(假設這個有三個結點:A,B,C):

第一階段:Prepare階段

A把申請修改的請求Prepare Request發給全部的結點A,B,C。注意,Paxos算法會有一個Sequence Number(提案號,這個數不斷遞增,並且是惟一的,也就是說A和B不可能有相同的提案號),這個提案號會和修改請求一同發出,任何結點在「Prepare階段」時都會拒絕其值小於當前提案號的請求。因此,結點A在向全部結點申請修改請求的時候,須要帶一個提案號,越新的提案,這個提案號就越是是最大的。

若是接收結點收到的提案號n大於其它結點發過來的提案號,這個結點會迴應Yes(本結點上最新的被批准提案號),並保證不接收其它<n的提案。這樣一來,結點上在Prepare階段里老是會對最新的提案作承諾。

優化:在上述 prepare 過程當中,若是任何一個結點發現存在一個更高編號的提案,則須要通知 提案人,提醒其中斷此次提案。

第二階段:Accept階段

若是提案者A收到了超過半數的結點返回的Yes,而後他就會向全部的結點發布Accept Request(一樣,須要帶上提案號n),若是沒有超過半數的話,那就返回失敗。

當結點們收到了Accept Request後,若是對於接收的結點來講,n是最大的了,那麼,它就會修改這個值,若是發現本身有一個更大的提案號,那麼,結點就會拒絕修改。

 

咱們能夠看以,這彷佛就是一個「兩段提交」的優化。其實,2PC/3PC都是分佈式一致性算法的殘次版本,Google Chubby的做者Mike Burrows說過這個世界上只有一種一致性算法,那就是Paxos,其它的算法都是殘次品。

 

 


 

CAP理論

  • 一致性(Consistency),一致性指「all nodes see the same data at the same time」,即更新操做成功並返回客戶端完成後,全部節點在同一時間的數據徹底一致;
  • 可用性(Availability),可用性指「Reads and writes always succeed」,即服務一直可用,並且是正常響應時間;
  • 分區容錯性(Partition tolerance),分區容錯性指「the system continues to operate despite arbitrary message loss or failure of part of the system」,即分佈式系統在遇到某節點或網絡分區故障的時候,仍然可以對外提供知足一致性和可用性的服務;

 

CAP理論爲:一個分佈式系統最多隻能同時知足一致性(Consistency)、可用性(Availability)和分區容錯性(Partition tolerance)這三項中的兩項。

對於多數大型互聯網應用的場景,主機衆多、部署分散,並且如今的集羣規模愈來愈大,因此節點故障、網絡故障是常態,並且要保證服務可用性達到N個9,即保證P和A,捨棄C(退而求其次保證最終一致性)。雖然某些地方會影響客戶體驗,但沒達到形成用戶流程的嚴重程度。

但對於銀行等金融機構,C必須保證。網絡發生故障寧肯中止服務,這是保證CA,捨棄P。

 

 

ACID理論

數據庫事務(Transaction)是指做爲單個邏輯工做單元執行的一系列操做,要麼徹底地執行,要麼徹底地不執行。

一方面,當多個應用程序併發訪問數據庫時,事務能夠在應用程序間提供一個隔離方法,防止互相干擾。另外一方面,事務爲數據庫操做序列提供了一個從失敗恢復正常的方法。

事物有下面4個特性:

  • 原子性(Atomicity),事務的原子性是指事務中的操做不可拆分,只容許所有執行或者所有不執行;
  • 一致性(Consistency),事務的一致性是指事務的執行不能破壞數據庫的一致性,一致性也稱爲完整性。一個事務在執行後,數據庫必須從一個一致性狀態轉變爲另外一個一致性狀態;
  • 隔離型(Isolation),事務的隔離型是指併發的事務相互隔離,不能互相干擾;
  • 持久性(Durability),事務的持久性是指事務一旦提交,對數據的狀態變動應該被永久保存;

 

實際工做中事務幾乎都是併發的,徹底作到互相之間不干擾會嚴重犧牲性能,爲了平衡隔離型和性能,SQL92規範定義了四個事務隔離級別:

  1. 讀未提交(Read Uncommitted),另外一個事務修改了數據,但還沒有提交,而本事務中的SELECT會讀到這些未被提交的數據(髒讀)。髒讀是指另外一個事務修改了數據,但還沒有提交,而本事務中的SELECT會讀到這些未被提交的數據。
  2. 讀已提交(Read Committed),本事務讀取到的是最新的數據(其餘事務提交後的)。問題是,在同一個事務裏,先後兩次相同的SELECT會讀到不一樣的結果(不可重複讀)。不可重複讀是指同一個事務執行過程當中,另一個事務提交了新數據,所以本事務前後兩次讀到的數據結果會不一致。
  3. 可重複讀(Repeatable Read),在同一個事務裏,SELECT的結果是事務開始時間點的狀態,一樣的SELECT操做讀到的結果會是一致的。可是,會有幻讀現象。不可重複讀保證了同一個事務裏,查詢的結果都是事務開始時的狀態(一致性)。可是,若是另外一個事務同時提交了新數據,本事務再更新時,就會發現了這些新數據,貌似以前讀到的數據是幻覺,這就是幻讀。
  4. 串行化(Serializable),全部事務只能一個接一個串行執行,不能併發。

事務隔離級別越高,越能保證數據的一致性,但對併發性能影響越大,一致性和高性能必須有所取捨或折中。

通常狀況下,多數應用程序能夠選擇將數據庫的隔離級別設置爲讀已提交,這樣能夠避免髒讀,也能夠獲得不錯的併發性能。儘管這個隔離級別會致使不可重複度、幻讀,但這種個別場合應用程序能夠經過主動加鎖進行併發控制。

 

 

BASE理論

BASE理論是對CAP理論的延伸,核心思想是即便沒法作到強一致性(Strong Consistency,CAP的一致性就是強一致性),但應用能夠採用適合的方式達到最終一致性(Eventual Consitency)。

  • 基本可用(Basically Available),基本可用是指分佈式系統在出現故障的時候,容許損失部分可用性,即保證核心可用;
  • 軟狀態( Soft State),軟狀態是指容許系統存在中間狀態,而該中間狀態不會影響系統總體可用性。分佈式存儲中通常一份數據至少會有三個副本,容許不一樣節點間副本同步的延時就是軟狀態的體現。mysql replication的異步複製也是一種體現;
  • 最終一致性( Eventual Consistency),最終一致性是指系統中的全部數據副本通過必定時間後,最終可以達到一致的狀態。弱一致性和強一致性相反,最終一致性是弱一致性的一種特殊狀況。

 

BASE支持的是大型分佈式系統,提出經過犧牲強一致性得到高可用性。

相關文章
相關標籤/搜索