接受」不完美「:分佈式事務學習總結

做爲一個前端專業的人來講,對於事務的理解,一直停留在「要麼都成功,要麼都不成功」的小白階段。既然本身將2018年定義爲」深刻理解「的一年,那麼就從深刻理解事務開始吧。前端

什麼是事務?

正如文章開頭所說的:事務是一系列的動做,這些動做必須所有完成,若是有一個失敗,那麼事務就會回滾到最開始的狀態,彷彿什麼都沒發生過同樣。在企業級應用的開發過程當中,事務管理是必不可少的技術,用來確保數據的完整性和一致性。數據庫

事務有四個特性,也就是常常被提到的ACID:編程

  • 原子性(Atomicity):所謂的原子性就是說,在整個事務中的全部操做,要麼所有完成,要麼所有不作,沒有中間狀態。對於事務在執行中發生錯誤,全部的操做都會被回滾,整個事務就像從沒被執行過同樣。
  • 一致性(Consistency):事務的執行必須保證系統的一致性,就拿轉帳爲例,A有500元,B有300元,若是在一個事務裏A成功轉給B50元,那麼無論併發多少,無論發生什麼,只要事務執行成功了,那麼最後A帳戶必定是450元,B帳戶必定是350元。
  • 隔離性(Isolation):所謂的隔離性就是說,事務與事務之間不會互相影響,一個事務的中間狀態不會被其餘事務感知。
  • 持久性(Durability):所謂的持久性,就是說一單事務完成了,那麼事務對數據所作的變動就徹底保存在了數據庫中,即便發生停電,系統宕機也是如此。

上面咱們說到的事務,也能夠稱爲是」本地事務「。目前許多框架,都可以很方便的支持本地事務。好比Spring Boot,只須要在方法前加上」@Transaction「的註解,就能夠愉快的使用事務了。安全

可是,事務到此未知就結束了嗎?不是的,隨着企業應用愈來愈複雜,應用的架構也從單體架構演變到了SOA,還有如今煊赫一時的微服務。這時候,又出現了分佈式事務的概念。網絡

分佈式事務

分佈式事務,簡單來講就是指對數據庫的處理操做分佈在不一樣的節點之上,並且操做的數據,分佈於不一樣的數據庫。分佈式事務,須要保證不一樣數據庫的數據一致性。架構

分佈式事務產生的緣由

數據庫分庫分表

處於數據量或者數據隔離的考慮,實際開發中須要進行分庫分表。原來一個庫如今變成了多個庫,這時候要保證數據一致性,就要用到分佈式事務。
異步確保型併發

應用SOA化

所謂的SOA話,就是業務的服務化。好比原來單機支撐了整個電商網站,如今對整個網站進行拆解,分離出了訂單中心、用戶中心、庫存中心。對於訂單中心,有專門的數據庫存儲訂單信息,用戶中心也有專門的數據庫存儲用戶信息,庫存中心也會有專門的數據庫存儲庫存信息。這時候若是要同時對訂單和庫存進行操做,那麼就會涉及到訂單數據庫和庫存數據庫,爲了保證數據一致性,就須要用到分佈式事務。
app

CPA與BASE

說到分佈式事務,就離不開CPA原則與BASE方案。框架

CPA

CPA指的是,在一個分佈式系統中,一致性(C)、可用性(A)、分區容錯性(P),三者不可兼得。CPA是NoSQL數據庫的基石。異步

  • 一致性:在分佈式系統中的全部數據備份,在同一時刻是否一樣的值。(等同於全部節點訪問同一份最新的數據副本)
  • 可用性:在集羣中一部分節點故障後,集羣總體是否還能響應客戶端的讀寫請求。(對數據更新具有高可用性)
  • 分區容錯性:以實際效果而言,分區至關於對通訊的時限要求。系統若是不能在時限內達成數據一致性,就意味着發生了分區的狀況,必須就當前操做在C和A之間作出選擇。

CAP理論就是說在分佈式存儲系統中,最多隻能實現上面的兩點。而因爲當前的網絡硬件確定會出現延遲丟包等問題,因此分區容忍性是咱們必須須要實現的。因此咱們只能在一致性和可用性之間進行權衡,沒有NoSQL系統能同時保證這三點。

BASE

BASE就是爲了解決關係數據庫強一致性引發的問題而引發的可用性下降而提出的解決方案。

BASE是下面三個術語的縮寫:

  • 基本可用(Basically Available)
  • 軟狀態(Soft state)
  • 最終一致(Eventually consistent)

常見的分佈式事務解決方案

兩階段提交

兩階段提交(Two Phase Commit, 2PC), 具備強一致性, 是CP系統的一種典型實現,常見的標準是XA,JTA等。例如Oracle的數據庫支持XA。

下面是兩階段提交的示意圖:
異步確保型
圖的上半是兩階段提交成功的演示, 下半是兩階段提交失敗的演示。

兩階段提交目前並非主流的解決方案,其主要緣由是:協調者須要等待全部參與者發出yes請求,或者一個參與者發出no請求後,才能執行提交或者終端操做。這會形成長時間鎖住多個資源,形成性能瓶頸。若是參與者有一個耗時長的操做, 性能損耗會更明顯;還有一個缺點,就是實現複雜,不利於系統的擴展。

TCC(Try-Confirm-Cancel)

TCC, 是基於補償型事務的AP系統的一種實現, 具備最終一致性。所謂的TCC編程模式,也是兩階段提交的一個變種。TCC提供了一個編程框架,將整個業務邏輯分爲三塊:Try、Confirm和Cancel三個操做。以在線下單爲例,Try階段會去扣庫存,Confirm階段則是去更新訂單狀態,若是更新訂單失敗,則進入Cancel階段,會去恢復庫存。總之,TCC就是經過代碼人爲實現了兩階段提交,不一樣的業務場景所寫的代碼都不同,複雜度也不同,所以,這種模式並不能很好地被複用。

異步確保型

經過將一系列同步的事務操做變爲基於消息執行的異步操做, 避免了分佈式事務中的同步阻塞操做的影響。基於消息執行就是基於消息中間件的兩階段提交,本質上是對消息中間件的一種特殊利用,它是將本地事務和發消息放在了一個分佈式事務裏,保證要麼本地操做成功成功而且對外發消息成功,要麼二者都失敗,開源的RocketMQ就支持這一特性,具體原理以下:
異步確保型

執行步驟以下:

  1. MQ發送方發送遠程事務消息到MQ Server;
  2. MQ Server給予響應, 代表事務消息已成功到達MQ Server.
  3. MQ發送方Commit本地事務.
  4. 若本地事務Commit成功, 則通知MQ Server容許對應事務消息被消費; 若本地事務失敗, 則通知MQ Server對應事務消息應被丟棄.
  5. 若MQ發送方超時未對MQ Server做出本地事務執行狀態的反饋, 那麼須要MQ Servfer向MQ發送方主動回查事務狀態, 以決定事務消息是否能被消費.
  6. 當得知本地事務執行成功時, MQ Server容許MQ訂閱方消費本條事務消息.

須要額外說明的一點, 就是事務消息投遞到MQ訂閱方後, 並不必定可以成功執行. 須要MQ訂閱方主動給予消費反饋(ack)

  • 若是MQ訂閱方執行遠程事務成功, 則給予消費成功的ack, 那麼MQ Server能夠安全將事務消息移除;
  • 若是執行失敗, MQ Server須要對消息從新投遞, 直至消費成功.
  • 根據業務邏輯的具體實現不一樣,還可能須要對消息中間件增長消息不重複, 不亂序等其它要求.

此方案適用於執行週期較長,實時性要求不高的場景。

最大努力通知型

這是分佈式事務中要求最低的一種, 也能夠經過消息中間件實現, 與前面異步確保型操做不一樣的一點是, 在消息由MQ Server投遞到消費者以後, 容許在達到最大重試次數以後正常結束事務.這種方案適用於交易結果消息的通知等

微服務的事務

最近兩年,微服務的呼聲愈來愈高,不可避免的,微服務也會面臨事務的困擾。

  • 首先,對於微服務架構來講,數據訪問變得更加複雜,這是由於數據都是微服務私有的,惟一可訪問的方式就是經過 API。這種打包數據訪問方式使得微服務之間鬆耦合,而且彼此之間獨立,更容易進行性能擴展。
  • 其次,不一樣的微服務常用不一樣的數據庫。應用會產生各類不一樣類型的數據,關係型數據庫並不必定是最佳選擇基於微服務的應用通常都使用 SQL 和 NoSQL 結合的模式。可是這些非關係型數據大多數並不支持 2PC。

總結

事務,尤爲是分佈式事務,是一個很大的話題,除了上述列出的幾種解決方案,根據不一樣的業務要求,還有許多其餘的解決方案。按照控制力度,分佈式事務分爲部分控制和徹底控制兩種:

  • 部分控制就是各類變種的兩階段提交,包括上面提到的異步確保型、TCC模式
  • 徹底控制就是徹底實現兩階段提交。部分控制的好處是併發量和性能很好,缺點是數據一致性減弱了,徹底控制則是犧牲了性能,保障了一致性。具體用哪一種方式,最終仍是取決於業務場景。
相關文章
相關標籤/搜索