分布式事務了解嗎?你們是如何解決分布式事務問題的?

2022-03-09 06:37:13 字數 2823 閱讀 8507

只要聊到你做了分布式系統,必問分布式事務,你對分布式事務一無所知的話,確實會很坑,你起碼得知道有哪些方案,一般怎麼來做,每個方案的優缺點是什麼。

現在面試,分布式系統成了標配,而分布式系統帶來的分布式事務也成了標配了。因為你做系統肯定要用事務吧,如果是分布式系統,肯定要用分布式事務吧。先不說你搞過沒有,起碼你得明白有哪幾種方案,每種方案可能有啥坑?比如 tcc 方案的網路問題、xa 方案的一致性問題。

分布式事務的實現主要有以下 5 種方案:

所謂的 xa 方案,即:兩階段提交,有乙個事務管理器的概念,負責協調多個資料庫(資源管理器)的事務,事務管理器先問問各個資料庫你準備好了嗎?如果每個資料庫都回覆 ok,那麼就正式提交事務,在各個資料庫上執行操作;如果任何其中乙個資料庫回答不 ok,那麼就回滾事務。

這種分布式事務方案,比較適合單塊應用裡,跨多個庫的分布式事務,而且因為嚴重依賴於資料庫層面來搞定複雜的事務,效率很低,絕對不適合高併發的場景。如果要玩兒,那麼基於spring + jta就可以搞定,自己隨便蒐個 demo 看看就知道了。

這個方案,我們很少用,一般來說某個系統內部如果出現跨多個庫的這麼乙個操作,是不合規的。我可以給大家介紹一下, 現在微服務,乙個大的系統分成幾十個甚至幾百個服務。一般來說,我們的規定和規範,是要求每個服務只能操作自己對應的乙個資料庫。

如果你要操作別的服務對應的庫,不允許直連別的服務的庫,違反微服務架構的規範,你隨便交叉胡亂訪問,幾百個服務的話,全體亂套,這樣的一套服務是沒法管理的,沒法治理的,可能會出現資料被別人改錯,自己的庫被別人寫掛等情況。

如果你要操作別人的服務的庫,你必須是通過呼叫別的服務的介面來實現,絕對不允許交叉訪問別人的資料庫。

tcc 的全稱是:tryconfirmcancel

這種方案說實話幾乎很少人使用,我們用的也比較少,但是也有使用的場景。因為這個事務回滾實際上是嚴重依賴於你自己寫**來回滾和補償了,會造成補償**巨大,非常之噁心。

比如說我們,一般來說跟錢相關的,跟錢打交道的,支付、交易相關的場景,我們會用 tcc,嚴格保證分布式事務要麼全部成功,要麼全部自動回滾,嚴格保證資金的正確性,保證在資金上不會出現問題。

而且最好是你的各個業務執行的時間都比較短。

但是說實話,一般盡量別這麼搞,自己手寫回滾邏輯,或者是補償邏輯,實在太噁心了,那個業務**是很難維護的。

本地訊息表其實是國外的 ebay 搞出來的這麼一套思想。

這個大概意思是這樣的:

a 系統在自己本地乙個事務裡操作同時,插入一條資料到訊息表;

接著 a 系統將這個訊息傳送到 mq 中去;

b 系統接收到訊息之後,在乙個事務裡,往自己本地訊息表裡插入一條資料,同時執行其他的業務操作,如果這個訊息已經被處理過了,那麼此時這個事務會回滾,這樣保證不會重複處理訊息;

b 系統執行成功之後,就會更新自己本地訊息表的狀態以及 a 系統訊息表的狀態;

如果 b 系統處理失敗了,那麼就不會更新訊息表狀態,那麼此時 a 系統會定時掃瞄自己的訊息表,如果有未處理的訊息,會再次傳送到 mq 中去,讓 b 再次處理;

這個方案保證了最終一致性,哪怕 b 事務失敗了,但是 a 會不斷重發訊息,直到 b 那邊成功為止。

這個方案說實話最大的問題就在於嚴重依賴於資料庫的訊息表來管理事務啥的,如果是高併發場景咋辦呢?咋擴充套件呢?所以一般確實很少用。

這個的意思,就是乾脆不要用本地的訊息表了,直接基於 mq 來實現事務。比如阿里的 rocketmq 就支援訊息事務。

大概的意思就是:

a 系統先傳送乙個 prepared 訊息到 mq,如果這個 prepared 訊息傳送失敗那麼就直接取消操作別執行了;

如果這個訊息傳送成功過了,那麼接著執行本地事務,如果成功就告訴 mq 傳送確認訊息,如果失敗就告訴 mq 回滾訊息;

如果傳送了確認訊息,那麼此時 b 系統會接收到確認訊息,然後執行本地的事務;

mq 會自動定時輪詢所有 prepared 訊息**你的介面,問你,這個訊息是不是本地事務處理失敗了,所有沒傳送確認的訊息,是繼續重試還是回滾?一般來說這裡你就可以查下資料庫看之前本地事務是否執行,如果回滾了,那麼這裡也回滾吧。這個就是避免可能本地事務執行成功了,而確認訊息卻傳送失敗了。

這個方案裡,要是系統 b 的事務失敗了咋辦?重試咯,自動不斷重試直到成功,如果實在是不行,要麼就是針對重要的資金類業務進行回滾,比如 b 系統本地回滾後,想辦法通知系統 a 也回滾;或者是傳送報警由人工來手工回滾和補償。

這個還是比較合適的,目前國內網際網路公司大都是這麼玩兒的,要不你舉用 rocketmq 支援的,要不你就自己基於類似 activemq?rabbitmq?自己封裝一套類似的邏輯出來,總之思路就是這樣子的。

這個方案的大致意思就是:

系統 a 本地事務執行完之後,傳送個訊息到 mq;

這裡會有個專門消費 mq 的最大努力通知服務,這個服務會消費 mq 然後寫入資料庫中記錄下來,或者是放入個記憶體佇列也可以,接著呼叫系統 b 的介面;

要是系統 b 執行成功就 ok 了;要是系統 b 執行失敗了,那麼最大努力通知服務就定時嘗試重新呼叫系統 b,反覆 n 次,最後還是不行就放棄。

如果你真的被問到,可以這麼說,我們某某特別嚴格的場景,用的是 tcc 來保證強一致性;然後其他的一些場景基於阿里的 rocketmq 來實現分布式事務。

你找乙個嚴格資金要求絕對不能錯的場景,你可以說你是用的 tcc 方案;如果是一般的分布式事務場景,訂單插入之後要呼叫庫存服務更新庫存,庫存資料沒有資金那麼的敏感,可以用可靠訊息最終一致性方案。

友情提示一下,rocketmq 3.2.6 之前的版本,是可以按照上面的思路來的,但是之後介面做了一些改變,我這裡不再贅述了。

當然如果你願意,你可以參考可靠訊息最終一致性方案來自己實現一套分布式事務,比如基於其他mq 來玩兒。

解決分布式事務

1.分布式解決方案 2.非常詳細的乙個業務邏輯 至於消費端消費失敗?通過 返回訊息的狀態,過一段時間,rocketmq會繼續傳送 漲姿勢了 2段式 先查詢每個資料庫的狀態,ok了之後,第2段是本地執行然後提交事務。事務管理器 atomikos,jtom,bitromix 缺點是 一旦詢問的階段機器掛...

分布式鎖,分布式事務以及解決方案了解一下

一 分布式鎖 場景1 常規的我們多執行緒訪問同一 塊的時候,為了保證同一時間只能 由乙個執行緒訪問,保證資料安全一致性,通常我們使用synchronized關鍵字來對方法加鎖,以達到保證資料安全性。場景2 現在越來越多的專案,為了追求效能與高併發,採用了soa架構,微服務架構,於是就會出現多個模組單...

分布式服務如何設計分布式事務

1 如果a b c強相關 考慮採用tcc框架 try confirm cancel bytetcc,himly 阿里的fescar,seata 推薦使用seata tcc框架 2 如果a 與bc並不強相關 考慮可靠訊息最終一致性解決方案,例如a成功後通過傳送kafka事件,bc監聽事件來處理。roc...