分布式事務

2021-09-01 15:36:20 字數 3388 閱讀 2968

分布式事務

現在遇到了幾個專案,這些專案都有乙個共同特點,就是要求分布式事務。能夠滿足跨系統的保持資料的一致性。舉個簡單例子,我沒錢買房,問老婆借了1萬塊,到期了,該還給老婆了,那就轉賬吧。如圖:

我的銀行卡是招商銀行的,老婆的銀行卡是中國銀行的,很顯然這就是個分布式事務了,招行要完成的動作是a(我的賬號)-10000, 中行的動作時b+10000,兩個動作比如同時成功才ok,如圖。

上網查了一下,這種分布式事務是有個開放協議的叫x/open,主要採用了兩部提交法演算法,異構的資料庫只要實現了這個協議,就可以完成分布式事務。這個需要底層資料庫的支援,因為這個協議和資料庫底層實現密切配合,需要各個資料庫的廠商自己完成符合xa協議的資料庫驅動,即driver.

很多銀行採用tuxedo中介軟體來控制分布式事務,其實這個x/open協議就是由 tuxedo的xa協議來的。

那麼這種分布式的事務結構,往往都是借助第三者的,架構圖如下:

有意思的是這個x/open協議的實質,是叫做什麼兩步提交。

第一步叫做預提交。即多個系統事務「幾乎」已經全部做好了,各個資料庫資源告訴事務管理器--「i am ready",

事務管理器最後一聲令下---「提交」,兩者真正提交,提交過程中出錯,全部回滾。

如果我們不知道有什麼xa協議,兩步提交,肯定有人會想,我自己寫個中介軟體來搞個逆向事務不可以嗎?這主要涉及到 01,10這兩種case, 01表示我a-10000的事務失敗,老婆的b+10000成功。那麼我先反推導出,老婆的逆事務為b-10000,我的逆事務為a+10000. 那麼如果老婆的事務成功,我的失敗,很顯然,老婆的事務要回退,那麼就再執行個逆事務,b-10000.貌似有道理,但是這個逆事務的「推理機」你會做嗎?似乎有難度哦。而且有問題的是,如果這個逆事務中途出現失敗該如何處理,逆事務的效率如何等等。這都是一堆的問題。

這個分布式事務最大的缺點就是會鎖定資料庫資源,兩步提交訊息反反覆覆,對網路不好的情況,肯定很難有擴充套件性。於是有人提出了基於訊息佇列的分布式事務處理。有這篇文章。

這篇文章的關鍵**就是這段,我看的有些稀里糊塗,說說自己的理解吧。

begin;

insert into transaction values(xid, $seller_id, $buyer_id, $amount);

put_to_queue 「update user(「seller」, $seller_id, amount);

put_to_queue 「update user(「buyer」, $buyer_id, amount);

commit;

for each message in queue

begin;

if cnt = 0 then

if message.type = 「seller」 then

update user set amt_sold = amt_sold + message.amount where id = message.user_id;

else

update user set amt_bought = amt_bought + message.amount where id = message.user_id;

endend

commit;

if 上述事務成功

dequeue message

endend

這段**的場景是 a資料有乙個交易的表transaction, b資料有個表user. 要求同時更新 transaction, user表。

文章最後這樣保持了弱一致性。可能看到這裡,你和我一樣困惑。

還是上圖那4中case:

00---(a 資料庫操作失敗,b資料庫操作失敗)

01---(a 資料庫操作失敗,b資料庫操作成功)

10---(a 資料庫操作成功,b資料庫操作失敗)

11---(a 資料庫操作成功,b資料庫操作成功)

begin;

insert into transaction values(xid, $seller_id, $buyer_id, $amount);

put_to_queue 「update user(「seller」, $seller_id, amount);

put_to_queue 「update user(「buyer」, $buyer_id, amount);

commit;

這段**,我覺得應該加乙個約束,就是 新增佇列也應該在這個事務中,讓其保持執行順序的偏序,就是先插 transaction,然後 put_to_queue。因為有可能如果put_to_queue是個應用程式的話,很可能是先put_to_queue,然後插transaction,這樣會導致01這種case出現,那麼就會產生不一致性。(放進佇列成功,但是插入由於unique的限制失敗了)。如果能保證有這個順序性,那麼00,01這種case就不會出現.

那我們大膽假設這個訊息佇列也是資料庫中的乙個id自增的表。那麼10這種情況會不會出現呢?也不會!根據單個資料庫事務一致性。那麼最後只剩下11這種case了。

後面的**,就是a機器的佇列傳到b,b根據佇列中的資料來執行動作。其實我們分析一下,a和b之間的佇列的傳輸本身就存在不一致風險,斷電了怎麼辦,佇列中中資料沒了,但是a資料庫資料已經提交了,怎麼辦?所以文章說實現了弱一致性,這裡面只不過玩了個風險置換的遊戲,如果這種風險發生的概率很高,很顯然這是不可取的。

這段**的核心思想擯棄(00,01,10這3種case, 只留11z這種case)就是a資料庫成功,那麼運算元據庫b的操作我通過訊息佇列或者其他備份措施,使其能夠正確到達b機器,b機器也能百分之百完成,那麼資料就滿足一致性! 恰恰,這還是有風險的,我們需要找到一種機制讓這種風險不存在,或者無限小。

誰能告訴我?!其實一段資料從a機器轉移到b機器,通過某種協議還是100%做到的!不過這個協議應該有些複雜。所以文章最後說,如果專案時間短,還是用xa協議,分布式事務處理,如果不急,就可以採用訊息佇列,而且開發這個訊息佇列還是有些複雜的。

最後,如果不是資料庫之間的資料一致,那又改如何處理呢?

為什麼說若一致性呢,因為10這種情況也是能出現的,a資料庫提交成功,b提交不成功(由於欄位的unique限制等,二步提交法,第一步就會去跑一邊事務,如果能跑,就進入第二步,如果不能跑,就通知兩機器撤銷事務)那麼,很顯然,我們明顯是可以預料b資料庫的事務是可以「百分百完成的」。那麼這個思想,就是把單機的事務控制,比用利用log, 然後轉移log,到b機去執行log,不過這種思想還是有欠缺的。

分布式 分布式事務

是資料庫執行過程中的乙個邏輯單位,由乙個有限的資料庫操作序列構成。事務的acid四大特性 原子性 atomicity 事務作為乙個整體被執行。一致性 consistency 從乙個一致的狀態轉換到另乙個一致的狀態。隔離性 isolation 多個事務併發執行時,併發事務之間互相影響的程度。永續性 d...

分布式事務 分布式事務的實現

如果在多個服務中需要對不同的資料庫進行操作。因為不同服務操作的資料庫都不同,所以保證在同乙個事務中完成操作顯然是不科學的。那實現分布式事務的思想 1 方法入口,建立一條日誌記錄,狀態定義為初始狀態,即儲存本條日誌記錄 可以儲存在資料庫中,也可以寫出到本地磁碟檔案 2 可以在非同步執行緒或在定時任務中...

分布式之分布式事務

被人問到分布式事務,之前學rabbitmq 的時候學到過rabbitmq 高階的事務,因為沒有用過,所有沒有回答好。這裡總結一下。1.單機版事務。事務的四大特性 acid a.原子性 b.一致性 c.隔離性 d.永續性 單機事務可以通過設定事務的隔離級別 參見spring 的事務隔離級別 2.分布式...