分佈式事務[1]分佈式事務概述

原文鏈接:http://www.tianshouzhi.com/api/tutorials/distributed_transaction

1.0 分佈式事務概述

 2018-02-05 02:05:26  17,341  8

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

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

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

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

   DTP 參考模型: <<Distributed Transaction Processing: Reference Model>>

   DTP XA規範: << Distributed Transaction Processing: The XA Specification>>

 

 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分佈式事務的支持有以下介紹:

https://dev.mysql.com/doc/refman/5.7/en/xa.html

 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, SERIALIZABLE may be preferred if your applications are sensitive to read phenomena. REPEATABLE READ 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)的改進版本。參考維基百科:https://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理論。文章鏈接:https://queue.acm.org/detail.cfm?id=1394128

    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(兩階段型、補償型)

 

參考文檔:

http://www.hollischuang.com/archives/666

http://www.cnblogs.com/hxsyl/p/4381980.html

http://blog.csdn.net/hu_zhiting/article/details/77060582

https://www.zhihu.com/question/31813039

https://my.oschina.net/foodon/blog/372703

http://blog.jobbole.com/95632/

http://www.jianshu.com/p/6c1fd2420274

http://www.linuxidc.com/Linux/2015-11/124942.htm

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章