注冊用戶即可下載全站資源 關注Java幫幫微信公眾號
 

分布式事務概述

24
發表時間:2018-12-11 14:53

1、事務簡介

    事務(Transaction)是訪問并可能更新數據庫中各種數據項的一個程序執行單元(unit)。在關系數據庫中,一個事務由一組SQL語句組成。事務應該具有4個屬性:原子性、一致性、隔離性、持久性。這四個屬性通常稱為ACID特性。

    原子性(atomicity):個事務是一個不可分割的工作單位,事務中包括的諸操作要么都做,要么都不做。

    一致性(consistency):事務必須是使數據庫從一個一致性狀態變到另一個一致性狀態,事務的中間狀態不能被觀察到的。

    隔離性(isolation):一個事務的執行不能被其他事務干擾。即一個事務內部的操作及使用的數據對并發的其他事務是隔離的,并發執行的各個事務之間不能互相干擾。隔離性又分為四個級別:讀未提交(read uncommitted)、讀已提交(read committed,解決臟讀)、可重復讀(repeatable read,解決虛讀)、串行化(serializable,解決幻讀)。

   持久性(durability):持久性也稱永久性(permanence),指一個事務一旦提交,它對數據庫中數據的改變就應該是永久性的。接下來的其他操作或故障不應該對其有任何影響。

   任何事務機制在實現時,都應該考慮事務的ACID特性,包括:本地事務、分布式事務,及時不能都很好的滿足,也要考慮支持到什么程度。


2 本地事務

     大多數場景下,我們的應用都只需要操作單一的數據庫,這種情況下的事務稱之為本地事務(Local Transaction)。本地事務的ACID特性是數據庫直接提供支持。本地事務應用架構如下所示:

0B73AA36-93FE-4F88-ADDF-940CF369FB95.png

在JDBC編程中,我們通過java.sql.Connection對象來開啟、關閉或者提交事務。代碼如下所示:

  1. Connection conn = ... //獲取數據庫連接

  2. conn.setAutoCommit(false); //開啟事務

  3. try{

  4.   //...執行增刪改查sql

  5.   conn.commit(); //提交事務

  6. }catch (Exception e) {

  7.  conn.rollback();//事務回滾

  8. }finally{

  9.   conn.close();//關閉鏈接

  10. }

此外,很多java應用都整合了spring,并使用其聲明式事務管理功能來完成事務功能。一般使用的步驟如下:

   1、配置事務管理器。spring提供了一個PlatformTransactionManager接口,其有2個重要的實現類:

       DataSourceTransactionManager:用于支持本地事務,事實上,其內部也是通過操作java.sql.Connection來開啟、提交和回滾事務。

       JtaTransactionManager:用于支持分布式事務,其實現了JTA規范,使用XA協議進行兩階段提交。需要注意的是,這只是一個代理,我們需要為其提供一個JTA provider,一般是Java EE容器提供的事務協調器(Java EE server's transaction coordinator),也可以不依賴容器,配置一個本地的JTA provider。

   2、 在需要開啟的事務的bean的方法上添加@Transitional注解

   可以看到,spring除了支持本地事務,也支持分布式事務,下面我們先對分布式事務的典型應用場景進行介紹。


3 分布式事務典型場景  

  當下互聯網發展如火如荼,絕大部分公司都進行了數據庫拆分和服務化(SOA)。在這種情況下,完成某一個業務功能可能需要橫跨多個服務,操作多個數據庫。這就涉及到到了分布式事務,用需要操作的資源位于多個資源服務器上,而應用需要保證對于多個資源服務器的數據的操作,要么全部成功,要么全部失敗。本質上來說,分布式事務就是為了保證不同資源服務器的數據一致性。

典型的分布式事務場景:

1、跨庫事務

   跨庫事務指的是,一個應用某個功能需要操作多個庫,不同的庫中存儲不同的業務數據。筆者見過一個相對比較復雜的業務,一個業務中同時操作了9個庫。下圖演示了一個服務同時操作2個庫的情況:

9E8ADF29-420D-41F0-BC93-3B0BD5EB6A02.png

2、分庫分表

   通常一個庫數據量比較大或者預期未來的數據量比較大,都會進行水平拆分,也就是分庫分表。如下圖,將數據庫B拆分成了2個庫:

139B7837-4209-4B36-B0E8-446941C70708.png

   對于分庫分表的情況,一般開發人員都會使用一些數據庫中間件來降低sql操作的復雜性。如,對于sql:insert into user(id,name) values (1,"tianshouzhi"),(2,"wangxiaoxiao")。這條sql是操作單庫的語法,單庫情況下,可以保證事務的一致性。

   但是由于現在進行了分庫分表,開發人員希望將1號記錄插入分庫1,2號記錄插入分庫2。所以數據庫中間件要將其改寫為2條sql,分別插入兩個不同的分庫,此時要保證兩個庫要不都成功,要不都失敗,因此基本上所有的數據庫中間件都面臨著分布式事務的問題。

3、服務化(SOA)

   微服務架構是目前一個比較一個比較火的概念。例如上面筆者提到的一個案例,某個應用同時操作了9個庫,這樣的應用業務邏輯必然非常復雜,對于開發人員是極大的挑戰,應該拆分成不同的獨立服務,以簡化業務邏輯。拆分后,獨立服務之間通過RPC框架來進行遠程調用,實現彼此的通信。下圖演示了一個3個服務之間彼此調用的架構:

E5E5F08C-E57B-438C-A5B2-686DC5243254.png


   Service A完成某個功能需要直接操作數據庫,同時需要調用Service B和Service C,而Service B又同時操作了2個數據庫,Service C也操作了一個庫。需要保證這些跨服務的對多個數據庫的操作要不都成功,要不都失敗,實際上這可能是最典型的分布式事務場景。

   小結:上述討論的分布式事務場景中,無一例外的都直接或者間接的操作了多個數據庫。如何保證事務的ACID特性,對于分布式事務實現方案而言,是非常大的挑戰。同時,分布式事務實現方案還必須要考慮性能的問題,如果為了嚴格保證ACID特性,導致性能嚴重下降,那么對于一些要求快速響應的業務,是無法接受的。

4 X/Open DTP模型與XA規范

   X/Open,即現在的open group,是一個獨立的組織,主要負責制定各種行業技術標準。官網地址:。X/Open組織主要由各大知名公司或者廠商進行支持,這些組織不光遵循X/Open組織定義的行業技術標準,也參與到標準的制定。下圖展示了open group目前主要成員(官網截圖):

9A3AC451-E44F-47FB-A7D6-20FD18B65723.png

可以看到,中國人的驕傲,華為,赫然在列!!!此處應該有掌聲。

  就分布式事務處理(Distributed Transaction Processing,簡稱DTP)而言,X/Open主要提供了以下參考文檔:

  DTP 參考模型:

  DTP XA規范:


4.1 DTP模型

  1、模型元素

 在<<Distributed Transaction Processing: Reference Model>>第3版中,規定了構成DTP模型的5個基本元素:

  應用程序(Application Program ,簡稱AP):用于定義事務邊界(即定義事務的開始和結束),并且在事務邊界內對資源進行操作。

  資源管理器(Resource Manager,簡稱RM):如數據庫、文件系統等,并提供訪問資源的方式。

  事務管理器(Transaction Manager ,簡稱TM):負責分配事務唯一標識,監控事務的執行進度,并負責事務的提交、回滾等。

  通信資源管理器(Communication Resource Manager,簡稱CRM):控制一個TM域(TM domain)內或者跨TM域的分布式應用之間的通信。

  通信協議(Communication Protocol,簡稱CP):提供CRM提供的分布式應用節點之間的底層通信服務。

   其中由于通信資源管理器(Communication Resource Manager)和通信協議(Communication Protocol)是一對好基友,從Communication Protocol的簡稱CP上就可以看出來,兩個元素的關系不一般,因此有的文章在介紹DTP模型元素時,只提到了通信資源管理器....

  2、模型實例(Instance of the Model)

  一個DTP模型實例,至少有3個組成部分:AP、RMs、TM。如下所示:

F6921BEC-E492-4EB9-AC05-A7E79C6DE027.png

   這張圖類似于我們之前提到的跨庫事務的概念,即單個應用需要操作多個庫。在這里就是一個AP需要操作多個RM上的資源。AP通過TM來聲明一個全局事務,然后操作不同的RM上的資源,最后通知TM來提交或者回滾全局事務。

     特別的,如果分布式事務需要跨多個應用,類似于我們前面的提到的分布式事務場景中的服務化,那么每個模型實例中,還需要額外的加入一個通信資源管理器CRM。

   下圖中演示了2個模型實例,如何通過CRM來進行通信:

7B96339F-DF94-4A7F-8590-F81DB5BC7CDC.png

CRM作為多個模型實例之間通信的橋梁,主要作用如下:

  •   基本的通信能力:從這個角度,可以將CRM類比為RPC框架,模型實例之間通過RPC調用實現彼此的通信。這一點體現在AP、CRM之間的連線。

  •   事務傳播能力:與傳統RPC框架不同的是,CRM底層采用OSI TP(Open Systems Interconnection — Distributed Transaction Processing)通信服務,因此CRM具備事務傳播能力。這一點體現TM、CRM之間的連線。

 2、事務管理器作用域 (TM domain)

       一個TM domain中由一個或者多個模型實例組成,這些模型實例使用的都是同一個TM,但是操作的RMs各不相同,由TM來統一協調這些模型實例共同參與形成的全局事務(global transaction)。

下圖展示了一個由四個模型實例組成的TM Domain,這四個模型實例使用的都是同一個事務管理器TM1。


28EC2E8D-220B-4E0D-BF4A-058F1AD76909.png

   TM domain只是列出了最終參與到一個全局事務中,有哪些模型實例,并不關心這些模型實例之間的關系。這就好比,有一個班級,我們只是想知道這個班級中每位同學的名字,但是并不是關心誰是班長、誰是學習委員等。

   不過顯然的,當一個TM domain中存在多個模型實例時,模型實例彼此之間存在一定的層級調用關系。這就是全局事務的樹形結構。


 3 全局事務樹形結構(Global Transaction Tree Structure)

  當一個TM domain中,存在多個模型實例時,會形成一種樹形條用關系,如下圖所示:

95F05F13-D75B-4638-9BA1-6FF36B5A5ADC.png


其中:

   發起分布式事務的模型實例稱之為root節點,或者稱之為事務的發起者,其他的模型實例可以統稱為事務的參與者。事務發起者負責開啟整個全局事務,事務參與者各自負責執行自己的事務分支。

   而從模型實例之間的相互調用關系來說,調用方稱之為上游節點(Superior Node),被調用方稱之為下游節點(Subordinate Node)。


小結:通過對DTP模型的介紹,我們可以看出來,之前提到的分布式事務的幾種典型場景實際上在DTP模型中都包含了,甚至比我們考慮的還復雜。DTP模型從最早提出到現在已經有接近30年,到如今依然適用,不得不佩服模型的設計者是很有遠見的。


4.2 XA規范

    在DTP本地模型實例中,由AP、RMs和TM組成,不需要其他元素。AP、RM和TM之間,彼此都需要進行交互,如下圖所示:

93DC1C17-7C88-40A4-8595-F15E89F4CAA1.png

這張圖中(1)表示AP-RM的交互接口,(2)表示AP-TM的交互接口,(3)表示RM-TM的交互接口。關于這張圖,XA規范有以下描述:

The subject of this X/Open specification is interface (3) in the diagram above, the XA interface by which TMs and RMs interact.

For more details on this model and diagram, including detailed definitions of each component, see the referenced DTP guide.

   也就是說XA規范的最主要的作用是,就是定義了RM-TM的交互接口,下圖更加清晰了演示了XA規范在DTP模型中發揮作用的位置,從下圖中可以看出來,XA僅僅出現在RM和TM的連線上。

1578CD5A-2EE1-4F41-8DE8-B2F615F79571.png


   XA規范除了定義的RM-TM交互的接口(XA Interface)之外,還對兩階段提交協議進行了優化。 一些讀者可能會誤認為兩階段提交協議是在XA規范中提出來的。事實上: 兩階段協議(two-phase commit)是在OSI TP標準中提出的;在DTP參考模型(<<Distributed Transaction Processing: Reference Model>>)中,指定了全局事務的提交要使用two-phase commit協議;而XA規范(<< Distributed Transaction Processing: The XA Specification>>)只是定義了兩階段提交協議中需要使用到的接口,也就是上述提到的RM-TM交互的接口,因為兩階段提交過程中的參與方,只有TM和RMs。參見<<Distributed Transaction Processing: Reference Model>> 第3版 2.1節,原文如下:

Commitment Protocol

A commitment protocol is the synchronisation that occurs at transaction completion. The X/Open DTP Model follows the two-phase commit with presumed rollback1 protocol defined in the referenced OSI TP standards. A description of the basic protocol is given in Section 3.4.3 on page 13. In certain cases, a global transaction may be completed heuristically. Heuristic transaction completion is described in Section 3.4.5 on page 14.


4.2.1  XA Interface  

XA規范中定義的RM 和 TM交互的接口如下圖所示:

72A58A31-EEA8-474B-B542-8A2928E3CD5C.png


關于這些接口的詳細解釋,可以直接參考XA規范。后面在講解到mysql對XA事務的支持時,我們也會使用到部分命令。

 4.2.2 兩階段提交協議(2PC)

 兩階段提交協議(Two Phase Commit)不是在XA規范中提出,但是XA規范對其進行了優化,因此統一放到這里進行講解。而從字面意思來理解,Two Phase Commit,就是將提交(commit)過程劃分為2個階段(Phase):

D7087D1B-1E4D-4C0E-8BA4-B2A8B36D0132.png


  In Phase 1, the TM asks all RMs to prepare to commit (or prepare) transaction branches. This asks whether the RM can guarantee its ability to commit the transaction branch. An RM may have to query other entities internal to that RM.

   If an RM can commit its work, it records stably the information it needs to do so, then replies affirmatively. A negative reply reports failure for any reason. After making a negative reply and rolling back its work, the RM can discard any knowledge it has of the transaction branch.

  In Phase 2, the TM issues all RMs an actual request to commit or roll back the transaction branch, as the case may be. (Before issuing requests to commit, the TM stably records the fact that it decided to commit, as well as a list of all involved RMs.) All RMs commit or roll back changes to shared resources and then return status to the TM. The TM can then discard its knowledge of the global transaction.


階段1:

   TM通知各個RM準備提交它們的事務分支。如果RM判斷自己進行的工作可以被提交,那就就對工作內容進行持久化,再給TM肯定答復;要是發生了其他情況,那給TM的都是否定答復。在發送了否定答復并回滾了已經的工作后,RM就可以丟棄這個事務分支信息。

   以mysql數據庫為例,在第一階段,事務管理器向所有涉及到的數據庫服務器發出prepare"準備提交"請求,數據庫收到請求后執行數據修改和日志記錄等處理,處理完成后只是把事務的狀態改成"可以提交",然后把結果返回給事務管理器。

階段2

   TM根據階段1各個RM prepare的結果,決定是提交還是回滾事務。如果所有的RM都prepare成功,那么TM通知所有的RM進行提交;如果有RM prepare失敗的話,則TM通知所有RM回滾自己的事務分支。

     以mysql數據庫為例,如果第一階段中所有數據庫都prepare成功,那么事務管理器向數據庫服務器發出"確認提交"請求,數據庫服務器把事務的"可以提交"狀態改為"提交完成"狀態,然后返回應答。如果在第一階段內有任何一個數據庫的操作發生了錯誤,或者事務管理器收不到某個數據庫的回應,則認為事務失敗,回撤所有數據庫的事務。數據庫服務器收不到第二階段的確認提交請求,也會把"可以提交"的事務回撤。


XA規范對兩階段提交協議有2點優化:

Protocol Optimisations

? Read-only

      An RM can respond to the TM’s prepare request by asserting that the RM was not asked to update shared resources in this transaction branch. This response concludes the RM’s involvement in the transaction; the Phase 2 dialogue between the TM and this RM does not occur. The TM need not stably record, in its list of participating RMs, an RM that asserts a read-only role in the global transaction.

However, if the RM returns the read-only optimisation before all work on the global transaction is prepared, global serialisability1 cannot be guaranteed. This is because the RM may release transaction context, such as read locks, before all application activity for that global transaction is finished.

2.  One-phase Commit

   A TM can use one-phase commit if it knows that there is only one RM anywhere in the DTP system that is making changes to shared resources. In this optimisation, the TM makes its Phase 2 commit request without having made a Phase 1 prepare request. Since the RM decides the outcome of the transaction branch and forgets about the transaction branch before returning to the TM, there is no need for the TM to record stably these global transactions and, in some failure cases, the TM may not know the outcome.

只讀斷言

   在Phase 1中,RM可以斷言“我這邊不涉及數據增刪改”來答復TM的prepare請求,從而讓這個RM脫離當前的全局事務,從而免去了Phase 2。

這種優化發生在其他RM都完成prepare之前的話,使用了只讀斷言的RM早于AP其他動作(比如說這個RM返回那些只讀數據給AP)前,就釋放了相關數據的上下文(比如讀鎖之類的),這時候其他全局事務或者本地事務就有機會去改變這些數據,結果就是無法保障整個系統的可序列化特性——通俗點說那就會有臟讀的風險。

一階段提交

   如果需要增刪改的數據都在同一個RM上,TM可以使用一階段提交——跳過兩階段提交中的Phase 1,直接執行Phase 2。

這種優化的本質是跳過Phase 1,RM自行決定了事務分支的結果,并且在答復TM前就清除掉事務分支信息。對于這種優化的情況,TM實際上也沒有必要去可靠的記錄全局事務的信息,在一些異常的場景下,此時TM可能不知道事務分支的執行結果。

 

4.2.3  兩階段提交協議(2PC)存在的問題

二階段提交看起來確實能夠提供原子性的操作,但是不幸的是,二階段提交還是有幾個缺點的:

1、同步阻塞問題。兩階段提交方案下全局事務的ACID特性,是依賴于RM的。例如mysql5.7官方文檔關于對XA分布式事務的支持有以下介紹:

A global transaction involves several actions that are transactional in themselves, but that all must either complete successfully as a group, or all be rolled back as a group. In essence, this extends ACID properties “up a level” so that multiple ACID transactions can be executed in concert as components of a global operation that also has ACID properties. (As with nondistributed transactions, may be preferred if your applications are sensitive to read phenomena. may not be sufficient for distributed transactions.)


   大致含義是說,一個全局事務內部包含了多個獨立的事務分支,這一組事務分支要不都成功,要不都失敗。各個事務分支的ACID特性共同構成了全局事務的ACID特性。也就是將單個事務分支的支持的ACID特性提升一個層次(up a level)到分布式事務的范疇。

   括號中的內容的意思是: 即使在非分布事務中(即本地事務),如果對操作讀很敏感,我們也需要將事務隔離級別設置為SERIALIZABLE。而對于分布式事務來說,更是如此,可重復讀隔離級別不足以保證分布式事務一致性。

   也就是說,如果我們使用mysql來支持XA分布式事務的話,那么最好將事務隔離級別設置為SERIALIZABLE。 地球人都知道,SERIALIZABLE(串行化)是四個事務隔離級別中最高的一個級別,也是執行效率最低的一個級別。

2、單點故障。由于協調者的重要性,一旦協調者TM發生故障。參與者RM會一直阻塞下去。尤其在第二階段,協調者發生故障,那么所有的參與者還都處于鎖定事務資源的狀態中,而無法繼續完成事務操作。(如果是協調者掛掉,可以重新選舉一個協調者,但是無法解決因為協調者宕機導致的參與者處于阻塞狀態的問題)

3、數據不一致。在二階段提交的階段二中,當協調者向參與者發送commit請求之后,發生了局部網絡異常或者在發送commit請求過程中協調者發生了故障,這回導致只有一部分參與者接受到了commit請求。而在這部分參與者接到commit請求之后就會執行commit操作。但是其他部分未接到commit請求的機器則無法執行事務提交。于是整個分布式系統便出現了數據不一致性的現象。

由于二階段提交存在著諸如同步阻塞、單點問題等缺陷,所以,研究者們在二階段提交的基礎上做了改進,提出了三階段提交。


5 三階段提交協議(Three-phase commit)

   三階段提交(3PC),是二階段提交(2PC)的改進版本。參考維基百科:http://en.wikipedia.org/wiki/Three-phase_commit_protocol

與兩階段提交不同的是,三階段提交有兩個改動點。

   1、引入超時機制。同時在協調者和參與者中都引入超時機制。

   2、在第一階段和第二階段中插入一個準備階段。保證了在最后提交階段之前各參與節點的狀態是一致的。也就是說,除了引入超時機制之外,3PC把2PC的準備階段再次一分為二,這樣三階段提交就有CanCommit、PreCommit、DoCommit三個階段。

9AFDC04C-016D-4CA6-8C04-AE7702264AFC.png


CanCommit階段

   3PC的CanCommit階段其實和2PC的準備階段很像。協調者向參與者發送commit請求,參與者如果可以提交就返回Yes響應,否則返回No響應。

   1.事務詢問 協調者向參與者發送CanCommit請求。詢問是否可以執行事務提交操作。然后開始等待參與者的響應。

   2.響應反饋 參與者接到CanCommit請求之后,正常情況下,如果其自身認為可以順利執行事務,則返回Yes響應,并進入預備狀態。否則反饋No

PreCommit階段

   協調者根據參與者的反應情況來決定是否可以記性事務的PreCommit操作。根據響應情況,有以下兩種可能。

   假如協調者從所有的參與者獲得的反饋都是Yes響應,那么就會執行事務的預執行。

   1.發送預提交請求 協調者向參與者發送PreCommit請求,并進入Prepared階段。    

   2.事務預提交 參與者接收到PreCommit請求后,會執行事務操作,并將undo和redo信息記錄到事務日志中。

   3.響應反饋 如果參與者成功的執行了事務操作,則返回ACK響應,同時開始等待最終指令。

  假如有任何一個參與者向協調者發送了No響應,或者等待超時之后,協調者都沒有接到參與者的響應,那么就執行事務的中斷。

   1.發送中斷請求 協調者向所有參與者發送abort請求。

   2.中斷事務 參與者收到來自協調者的abort請求之后(或超時之后,仍未收到協調者的請求),執行事務的中斷。

doCommit階段

   該階段進行真正的事務提交,也可以分為以下兩種情況。

   Case 1:執行提交

   1.發送提交請求 協調接收到參與者發送的ACK響應,那么他將從預提交狀態進入到提交狀態。并向所有參與者發送doCommit請求。

   2.事務提交 參與者接收到doCommit請求之后,執行正式的事務提交。并在完成事務提交之后釋放所有事務資源。

   3.響應反饋 事務提交完之后,向協調者發送Ack響應。

   4.完成事務 協調者接收到所有參與者的ack響應之后,完成事務。

  Case 2:中斷事務 協調者沒有接收到參與者發送的ACK響應(可能是接受者發送的不是ACK響應,也可能響應超時),那么就會執行中斷事務。

   1.發送中斷請求 協調者向所有參與者發送abort請求

   2.事務回滾 參與者接收到abort請求之后,利用其在階段二記錄的undo信息來執行事務的回滾操作,并在完成回滾之后釋放所有的事務資源。

   3.反饋結果 參與者完成事務回滾之后,向協調者發送ACK消息

   4.中斷事務 協調者接收到參與者反饋的ACK消息之后,執行事務的中斷。


   在doCommit階段,如果參與者無法及時接收到來自協調者的doCommit或者rebort請求時,會在等待超時之后,會繼續進行事務的提交。(其實這個應該是基于概率來決定的,當進入第三階段時,說明參與者在第二階段已經收到了PreCommit請求,那么協調者產生PreCommit請求的前提條件是他在第二階段開始之前,收到所有參與者的CanCommit響應都是Yes。(一旦參與者收到了PreCommit,意味他知道大家其實都同意修改了)所以,一句話概括就是,當進入第三階段時,由于網絡超時等原因,雖然參與者沒有收到commit或者abort響應,但是他有理由相信:成功提交的幾率很大。 )


小結:2PC與3PC的區別

   相對于2PC,3PC主要解決的單點故障問題,并減少阻塞,因為一旦參與者無法及時收到來自協調者的信息之后,他會默認執行commit。而不會一直持有事務資源并處于阻塞狀態。但是這種機制也會導致數據一致性問題,因為,由于網絡原因,協調者發送的abort響應沒有及時被參與者接收到,那么參與者在等待超時之后執行了commit操作。這樣就和其他接到abort命令并執行回滾的參與者之間存在數據不一致的情況。

   了解了2PC和3PC之后,我們可以發現,無論是二階段提交還是三階段提交都無法徹底解決分布式的一致性問題。Google Chubby的作者Mike Burrows說過, there is only one consensus protocol, and that’s Paxos” – all other approaches are just broken versions of Paxos. 意即世上只有一種一致性算法,那就是Paxos,所有其他一致性算法都是Paxos算法的不完整版。后面的文章會介紹這個公認為難于理解但是行之有效的Paxos算法。  


6 BASE理論與柔性事務

6.1 經典的分布式系統理論-CAP

   2000年7月,加州大學伯克利分校的Eric Brewer教授在ACM PODC會議上提出CAP猜想。Brewer認為在設計一個大規模的分布式系統時會遇到三個特性:一致性(consistency)、可用性(Availability)、分區容錯(partition-tolerance),而一個分布式系統最多只能滿足其中的2項。2年后,麻省理工學院的Seth Gilbert和Nancy Lynch從理論上證明了CAP。之后,CAP理論正式成為分布式計算領域的公認定理。

   Image.png


1. 一致性

   一致性指“all nodes see the same data at the same time”,即更新操作成功并返回客戶端完成后,所有節點在同一時間的數據完全一致,不能存在中間狀態。例如對于電商系統用戶下單操作,庫存減少、用戶資金賬戶扣減、積分增加等操作必須在用戶下單操作完成后必須是一致的。不能出現類似于庫存已經減少,而用戶資金賬戶尚未扣減,積分也未增加的情況。如果出現了這種情況,那么就認為是不一致的。

   關于一致性,如果的確能像上面描述的那樣時刻保證客戶端看到的數據都是一致的,那么稱之為強一致性。如果允許存在中間狀態,只要求經過一段時間后,數據最終是一致的,則稱之為最終一致性。此外,如果允許存在部分數據不一致,那么就稱之為弱一致性。

2. 可用性

   可用性是指系統提供的服務必須一直處于可用的狀態,對于用戶的每一個操作請求總是能夠在有限的時間內返回結果。“有限的時間內”是指,對于用戶的一個操作請求,系統必須能夠在指定的時間內返回對應的處理結果,如果超過了這個時間范圍,那么系統就被認為是不可用的。試想,如果一個下單操作,為了保證分布式事務的一致性,需要10分鐘才能處理完,那么用戶顯然是無法忍受的。“返回結果”是可用性的另一個非常重要的指標,它要求系統在完成對用戶請求的處理后,返回一個正常的響應結果,不論這個結果是成功還是失敗。

3. 分區容錯性

   分布式系統在遇到任何網絡分區故障的時候,仍然需要能夠保證對外提供滿足一致性和可用性的服務,除非是整個網絡環境都發生了故障。


小結: 既然一個分布式系統無法同時滿足一致性、可用性、分區容錯性三個特點,我們就需要拋棄一個,需要明確的一點是,對于一個分布式系統而言,分區容錯性是一個最基本的要求。因為既然是一個分布式系統,那么分布式系統中的組件必然需要被部署到不同的節點,否則也就無所謂分布式系統了。而對于分布式系統而言,網絡問題又是一個必定會出現的異常情況,因此分區容錯性也就成為了一個分布式系統必然需要面對和解決的問題。因此系統架構師往往需要把精力花在如何根據業務特點在C(一致性)和A(可用性)之間尋求平衡。而前面我們提到的X/Open XA 兩階段提交協議的分布式事務方案,強調的就是一致性;由于可用性較低,實際應用的并不多。而基于BASE理論的柔性事務,強調的是可用性,目前大行其道,大部分互聯網公司采可能會優先采用這種方案。


6.2 BASE理論

   eBay的架構師Dan Pritchett源于對大規模分布式系統的實踐總結,在ACM上發表文章提出BASE理論。文章鏈接:

   BASE理論是對CAP理論的延伸,核心思想是即使無法做到強一致性(Strong Consistency,CAP的一致性就是強一致性),但應用可以采用適合的方式達到最終一致性(Eventual Consitency)。    

BASE是Basically Available(基本可用)、Soft state(軟狀態)和Eventually consistent(最終一致性)三個短語的縮寫。

   1. 基本可用(Basically Available)

       指分布式系統在出現不可預知故障的時候,允許損失部分可用性。

   2. 軟狀態( Soft State)

       指允許系統中的數據存在中間狀態,并認為該中間狀態的存在不會影響系統的整體可用性。

   3. 最終一致( Eventual Consistency)

       強調的是所有的數據更新操作,在經過一段時間的同步之后,最終都能夠達到一個一致的狀態。因此,最終一致性的本質是需要系統保證最終數據能夠達到一致,而不需要實時保證系統數據的強一致性。

   BASE理論面向的是大型高可用可擴展的分布式系統,和傳統的事物ACID特性是相反的。它完全不同于ACID的強一致性模型,而是通過犧牲強一致性來獲得可用性,并允許數據在一段時間內是不一致的,但最終達到一致狀態。但同時,在實際的分布式場景中,不同業務單元和組件對數據一致性的要求是不同的,因此在具體的分布式系統架構設計過程中,ACID特性和BASE理論往往又會結合在一起。

6.3 典型的柔性事務方案

    最大努力通知(非可靠消息、定期校對)

    可靠消息最終一致性(異步確保型)

    TCC(兩階段型、補償型)


支付寶贊助-Java幫幫社區
微信贊助-Java幫幫社區
Java幫幫公眾號生態

Java幫幫公眾號生態

總有一款適合你

Java幫幫-微信公眾號

Java幫幫-微信公眾號

將分享做到極致

Python幫幫-公眾號

Python幫幫-公眾號

人工智能,爬蟲,學習教程

大數據驛站-微信公眾號

大數據驛站-微信公眾號

一起在數據中成長

九點編程-公眾號

九點編程-公眾號

深夜九點學編程

程序員生活志-公眾號

程序員生活志-公眾號

互聯網,職場,程序員那些事兒

Java幫幫學習群生態

Java幫幫學習群生態

總有一款能幫到你

Java學習群

Java學習群

與大牛一起交流

大數據學習群

大數據學習群

在數據中成長

九點編程學習群

九點編程學習群

深夜九點學編程

python學習群

python學習群

人工智能,爬蟲

測試學習群

測試學習群

感受測試的魅力

Java幫幫生態承諾

Java幫幫生態承諾

一直堅守,不負重望

初心
勤儉
誠信
正義
分享
合作品牌 非盈利生態-優質內容分享傳播者
關于我們
友鏈申請
友鏈交換:加幫主QQ2524138991 留言即可 24小時內答復  
全站內容非商業用途,內容來源于網友,并遵循 許可,如有異議請聯系客服。
會員登錄
獲取驗證碼
登錄
登錄
我的資料
留言
回到頂部