分布式事務 解決方案

2021-08-20 02:08:33 字數 4111 閱讀 4143

一、先說說事物的四個特點:acid

*  a原子性:abc要麼都成功,要麼都失敗

*  c一致性:操作執行前後,資料要求一致,比如,ab賬號的錢加起來是500,a給b轉賬50,不管中間過程怎麼操作,最終要求ab的錢加起來還是500

*  i隔離性:abc都在幹活,要求他們之間互不干擾,即隔離的情況下併發執行

*  d永續性:事務一旦提交成功,那麼更新到資料庫中的資料是持久存在的

二、分布式解決方案:遵循base理論,事務拆分、實現最終一致性

當我們的單個資料庫的效能產生瓶頸的時候,我們可能會對資料庫進行分割槽,這裡所說的分割槽指的是物理分割槽,分割槽之後可能不同的庫就處於不同的伺服器上了,這個時候單個資料庫的acid已經不能適應這種情況了,而在這種acid的集群環境下,再想保證集群的acid幾乎是很難達到,或者即使能達到那麼效率和效能會大幅下降,最為關鍵的是再很難擴充套件新的分割槽了,這個時候如果再追求集群的acid會導致我們的系統變得很差,這時我們就需要引入乙個新的理論原則來適應這種集群的情況,就是 cap 原則或者叫cap定理,那麼cap定理指的是什麼呢?

cap定理

cap定理是由加州大學伯克利分校eric brewer教授提出來的,他指出web服務無法同時滿足一下3個屬性:

具體地講在分布式系統中,在任何資料庫設計中,乙個web應用至多只能同時支援上面的兩個屬性。顯然,任何橫向擴充套件策略都要依賴於資料分割槽。因此,設計人員必須在一致性與可用性之間做出選擇。

這個定理在迄今為止的分布式系統中都是適用的! 為什麼這麼說呢?

這個時候有同學可能會把資料庫的2pc(兩階段提交)搬出來說話了。ok,我們就來看一下資料庫的兩階段提交。

對資料庫分布式事務有了解的同學一定知道資料庫支援的2pc,又叫做 xa transactions。

mysql從5.5版本開始支援,sql server 2005 開始支援,oracle 7 開始支援。

其中,xa 是乙個兩階段提交協議,該協議分為以下兩個階段:

其中,如果有任何乙個資料庫否決此次提交,那麼所有資料庫都會被要求回滾它們在此事務中的那部分資訊。這樣做的缺陷是什麼呢? 咋看之下我們可以在資料庫分割槽之間獲得一致性。

如果cap 定理是對的,那麼它一定會影響到可用性。

如果說系統的可用性代表的是執行某項操作相關所有元件的可用性的和。那麼在兩階段提交的過程中,可用性就代表了涉及到的每乙個資料庫中可用性的和。我們假設兩階段提交的過程中每乙個資料庫都具有99.9%的可用性,那麼如果兩階段提交涉及到兩個資料庫,這個結果就是99.8%。根據系統可用性計算公式,假設每個月43200分鐘,99.9%的可用性就是43157分鐘, 99.8%的可用性就是43114分鐘,相當於每個月的宕機時間增加了43分鐘。

以上,可以驗證出來,cap定理從理論上來講是正確的,cap我們先看到這裡,等會再接著說。

base理論

在分布式系統中,我們往往追求的是可用性,它的重要程式比一致性要高,那麼如何實現高可用性呢? 前人已經給我們提出來了另外乙個理論,就是base理論,它是用來對cap定理進行進一步擴充的。base理論指的是:

base理論是對cap中的一致性和可用性進行乙個權衡的結果,理論的核心思想就是:我們無法做到強一致,但每個應用都可以根據自身的業務特點,採用適當的方式來使系統達到最終一致性(eventual consistency)。

有了以上理論之後,我們來看一下分布式事務的問題。

在分布式系統中,要實現分布式事務,無外乎那幾種解決方案。

一、兩階段提交(2pc)

和上一節中提到的資料庫xa事務一樣,兩階段提交就是使用xa協議的原理,我們可以從下面這個圖的流程來很容易的看出中間的一些比如commit和abort的細節。

兩階段提交這種解決方案屬於犧牲了一部分可用性來換取的一致性。在實現方面,在 .net 中,可以借助 transactionscop 提供的 api 來程式設計實現分布式系統中的兩階段提交,比如wcf中就有實現這部分功能。不過在多伺服器之間,需要依賴於dtc來完成事務一致性,windows下微軟搞的有msdtc服務,linux下就比較悲劇了。

另外說一句,transactionscop 預設不能用於非同步方法之間事務一致,因為事務上下文是儲存於當前執行緒中的,所以如果是在非同步方法,需要顯式的傳遞事務上下文。

優點: 盡量保證了資料的強一致,適合對資料強一致要求很高的關鍵領域。(其實也不能100%保證強一致)

缺點: 實現複雜,犧牲了可用性,對效能影響較大,不適合高併發高效能場景,如果分布式系統跨介面呼叫,目前 .net 界還沒有實現方案。

二、補償事務(tcc)

tcc 其實就是採用的補償機制,其核心思想是:針對每個操作,都要註冊乙個與其對應的確認和補償(撤銷)操作。它分為三個階段:

舉個例子,假入 bob 要向 smith 轉賬,思路大概是:

我們有乙個本地方法,裡面依次呼叫

1、首先在 try 階段,要先呼叫遠端介面把 smith 和 bob 的錢給凍結起來。

2、在 confirm 階段,執行遠端呼叫的轉賬的操作,轉賬成功進行解凍。

3、如果第2步執行成功,那麼轉賬成功,如果第二步執行失敗,則呼叫遠端凍結介面對應的解凍方法 (cancel)。

優點: 跟2pc比起來,實現以及流程相對簡單了一些,但資料的一致性比2pc也要差一些

缺點: 缺點還是比較明顯的,在2,3步中都有可能失敗。tcc屬於應用層的一種補償方式,所以需要程式設計師在實現的時候多寫很多補償的**,在一些場景中,一些業務流程可能用tcc不太好定義及處理。

三、本地訊息表(非同步確保)

本地訊息表這種實現方式應該是業界使用最多的,其核心思想是將分布式事務拆分成本地事務進行處理,這種思路是**於ebay。我們可以從下面的流程圖中看出其中的一些細節:

基本思路就是:

訊息生產方,需要額外建乙個訊息表,並記錄訊息傳送狀態。訊息表和業務資料要在乙個事務裡提交,也就是說他們要在乙個資料庫裡面。然後訊息會經過mq傳送到訊息的消費方。如果訊息傳送失敗,會進行重試傳送。

訊息消費方,需要處理這個訊息,並完成自己的業務邏輯。此時如果本地事務處理成功,表明已經處理成功了,如果處理失敗,那麼就會重試執行。如果是業務上面的失敗,可以給生產方傳送乙個業務補償訊息,通知生產方進行回滾等操作。

生產方和消費方定時掃瞄本地訊息表,把還沒處理完成的訊息或者失敗的訊息再傳送一遍。如果有靠譜的自動對賬補賬邏輯,這種方案還是非常實用的。

這種方案遵循base理論,採用的是最終一致性,筆者認為是這幾種方案裡面比較適合實際業務場景的,即不會出現像2pc那樣複雜的實現(當呼叫鏈很長的時候,2pc的可用性是非常低的),也不會像tcc那樣可能出現確認或者回滾不了的情況。

優點: 一種非常經典的實現,避免了分布式事務,實現了最終一致性。在 .net中 有現成的解決方案。

缺點: 訊息表會耦合到業務系統中,如果沒有封裝好的解決方案,會有很多雜活需要處理。

四、mq 事務訊息

有一些第三方的mq是支援事務訊息的,比如rocketmq,他們支援事務訊息的方式也是類似於採用的二階段提交,但是市面上一些主流的mq都是不支援事務訊息的,比如 rabbitmq 和 kafka 都不支援。

以阿里的 rocketmq 中介軟體為例,其思路大致為:

第一階段prepared訊息,會拿到訊息的位址。

第二階段執行本地事務,第三階段通過第一階段拿到的位址去訪問訊息,並修改狀態。

也就是說在業務方法內要想訊息佇列提交兩次請求,一次傳送訊息和一次確認訊息。如果確認訊息傳送失敗了rocketmq會定期掃瞄訊息集群中的事務訊息,這時候發現了prepared訊息,它會向訊息傳送者確認,所以生產方需要實現乙個check介面,rocketmq會根據傳送端設定的策略來決定是回滾還是繼續傳送確認訊息。這樣就保證了訊息傳送與本地事務同時成功或同時失敗。

遺憾的是,rocketmq並沒有 .net 客戶端。有關 rocketmq的更多訊息,大家可以檢視這篇部落格

優點: 實現了最終一致性,不需要依賴本地資料庫事務。

缺點: 實現難度大,主流mq不支援,沒有.net客戶端,rocketmq事務訊息部分**也未開源。

事務 分布式事務解決方案

事務acid特性 事務隔離級別 指的是讀和寫同時出現時出現的資料不一致問題。事務的一致性問題 存在問題問題描述 髒讀 dirty read 針對的是單條資料。即乙個更新操作a修改了某一條資料,但尚未提交該事務,此時另乙個讀操作b來查詢該條資料,讀到的是修改後的但尚未提交的資料。不可重複讀 unrep...

分布式事務解決方案

一 結合mq訊息中介軟體實現的可靠訊息最終一致性 二 tcc補償性事務解決 三 最大努力通知型方案 第一種方案 可靠訊息最終一致性,需要業務系統結合mq訊息中介軟體實現,在實現過程中需要保證訊息的成功傳送及成功消費。即需要通過業務系統控制mq的訊息狀態 第二種方案 tcc補償性,分為三個階段tryi...

分布式事務解決方案

當資料庫單錶一年產生的資料超過1000w,那麼就要考慮分庫分表,具體分庫分表的原理在此不做解釋,以後有空詳細說,簡單的說就是原來的乙個資料庫變成了多個資料庫。這時候,如果乙個操作既訪問01庫,又訪問02庫,而且要保證資料的一致性,那麼就要用到分布式事務。所謂的soa化,就是業務的服務化。比如原來單機...