經驗整理-1-分佈式事務-100-@

--------------------------分佈式事務--------------------------

你們公司是如何處理分佈式事務的?

特別嚴格的場景,用的是 TCC 來保證強一致性;然後其他的一些場景基於阿里的 RocketMQ 來實現分佈式事務。

網關調賬務記賬用的 TCC 強一致性方案;如果是一般的分佈式事務場景,訂單插入之後要調用庫存服務更新庫存,庫存數據沒有資金那麼的敏感,可以用可靠消息最終一致性方案

 

CAP理論?

一致性可用分區:想要數據強一致性安全,就會慢,可用性就差。要麼CP,要麼AP。


?分佈式事務解決方案有幾種?

①傳統模式使用Jta+Atomikos
②PC與3PC實現的區別
③支付回調通知補償型
④使用阿里巴巴TCC補償框架
⑤使用可靠消息模式
⑥使用LCN框架解決分佈式事務
⑦阿里GTS框架解決分佈式事務

重點解釋:

  • TCC 方案---Try、Confirm、Cancel
  • 可靠消息Mq最終一致性方案---rocketMq
  • 本地消息表---
  • XA 方案(Jta+Atomikos)---適合單系統裏,跨多個庫的分佈式事務,XA不合理(規定和規範,是要求每個服務只能操作自己對應的一個數據庫
  • 使用LCN框架解決分佈式事務
  • 最大努力通知方案(柔性事務BASE補償幾次)---適合被動方處理結果 不影響主動方的處理結果,如銀行通知、商戶通知,採用類似支付寶回調機制,但是,要考慮補償機制,重試機制,還要考慮冪等性,重複性問題。

 

-------------------TCC 方案-------------

?工作原理或實現原理?

TCC 的全稱是:Try、Confirm、Cancel。
Try 階段:這個階段說的是對各個服務的資源做檢測以及對資源進行鎖定或者預留。
Confirm 階段:這個階段說的是在各個服務中執行實際的操作。
Cancel 階段:如果任何一個服務的業務方法執行出錯,那麼這裏就需要進行補償,就是執行已經執行成功的業務邏輯的回滾操作。(把那些執行成功的回滾)

?的作用或優點或應用場景?

很少人使用,事務回滾實際上是嚴重依賴於你自己寫代碼來回滾和補償。
一般來說相關的,跟錢打交道的,支付交易相關的場景,我們會用 TCC,嚴格保證分佈式事務要麼全部成功,要麼全部自動回滾,嚴格保證資金的正確性,保證在資金上不會出現問題

?我搭建過,如何搭建?

?搭建和使用過程中遇到哪些問題?

?*與*的區別?

-------------------rabbitMQ可靠消息隊列最終一致性方案-------------

?rabbitMQ可靠消息隊列最終一致性方案,工作原理或實現原理?

(A 系統先發送一個 prepared 消息到 mq,如果這個 prepared 消息發送失敗那麼就直接取消操作別執行了;
如果這個消息發送成功過了,那麼接着執行本地事務,如果成功就告訴 mq 發送確認消息,如果失敗就告訴 mq 回滾消息;
如果發送了確認消息,那麼此時 B 系統會接收到確認消息,然後執行本地的事務;
mq 會自動定時輪詢所有 prepared 消息回調你的接口,問你,這個消息是不是本地事務處理失敗了,所有沒發送確認的消息,是繼續重試還是回滾?一般來說這裏你就可以查下數據庫看之前本地事務是否執行,如果回滾了,那麼這裏也回滾吧。這個就是避免可能本地事務執行成功了,而確認消息卻發送失敗了。
這個方案裏,要是系統 B 的事務失敗了咋辦?重試咯,自動不斷重試直到成功,如果實在是不行,要麼就是針對重要的資金類業務進行回滾,比如 B 系統本地回滾後,想辦法通知系統 A 也回滾;或者是發送報警由人工來手工回滾和補償。
這個還是比較合適的,目前國內互聯網公司大都是這麼玩兒的,要不你舉用 RocketMQ 支持的,要不你就自己基於類似 ActiveMQ?RabbitMQ?自己封裝一套類似的邏輯出來,總之思路就是這樣子的。)

利用MQ自帶的事務消息,少數支持如RocketMQ,主流的MQ都是不支持事務消息的,比如 RabbitMQ 和 Kafka 都不支持。
原理:(和上面三、本地消息表事務的改進版,相比優點在於發送者業務提交失敗隊列不會再下發到消費者,缺點在於沒考慮消費者是否消費到問題
RocketMQ(借鑑了兩階段提交理論--這個我考察過)有一個消息準備階段和提交階段。
準備階段,生產者發送準備消息到隊列。(消費者)MQ服務端收到準備消息後再反饋給生產者接收成功,此時也代表發送成功
提交階段,生產者提交本地業務塊的事物,再發送提交消息到隊列(中斷,沒發過去會走檢查機制)(消費者)MQ服務端收到提交消息後,真正開始下發到消費者,執行業務塊。
檢查機制,生產者要實現一個 check 接口,根據檢查結果,定義返回策略決定是 rollback 還是繼續 commit
這樣就保證了消息發送與本地事務同時成功或同時失敗。(並不保證消費端業務也一定執行成功)

?的作用或優點或應用場景?

?我搭建過,如何搭建?

?搭建和使用過程中遇到哪些問題?

?rabbitMQ版本?

發送者計數3次發送MQ失敗進入死信隊列,通知人工處理死信隊列,減少數據庫壓力),
示例:放款功能,P2P業務系統(下單)和網關係統(拆分存管和賬務下單)。(當然是舉例,網關很多不同的業務,開標、放款、債轉、還款等,重構代價比較大,業務迭代時間快,沒有時間重構,目前把壓力給我的賬務了,賬務是壓力上來了,不得不重構,如果沒壓力,公司不會支持去做重構,中小型公司普遍的現象)
現在要實現一個保證兩個系統分佈式系統一致性的思路:
示例1-跨系統間,
官方版
RabbitMQ解決分佈式事務原理: 採用最終一致性原理。需要保證以下三要素
1、確認生產者一定要將數據投遞到MQ服務器中(採用MQ消息確認機制)
2、MQ消費者消息能夠正確消費消息,採用手動ACK模式(注意重試冪等性問題)
3、如何保證第一個事務先執行,採用補償機制,在創建一個補單消費者進行監聽,如果訂單沒有創建成功,進行補單。


自已改進版
RabbitMQ解決分佈式事務原理: 採用最終一致性原理。需要保證以下三要素
1、確認生產者投遞,一定要將數據投遞到MQ服務器中(採用MQ發送消息確認機制
2、確認MQ消費者消費,消息能夠正確消費,採用手動ACK模式(注意重試冪等性問題,不要依賴隊列重試,走業務代碼重試)
3、保證第一個系統事務先執行:首先,隊列放在後,且catch隊列發送異常,不回滾。然後重寫生產者發送消息確認機制,響應失敗補償,3次告警。(減輕DB壓力)
真實項目舉例:
1. (先本地一致性)業務系統操作下單並巧用確認機制保證提交到隊列。當業務下單的時候,在本地同一個事務中(依靠數據庫本地事務保證一致性),業務下單操作後,把下單消息發往隊列中,直接提交事物(不用消息表,能捨棄強事物,減少DB操作),當然這裏也會對發送MQ階段做近似一致性:重寫業務生產者發送消息確認機制,並把CorrelationData 類重寫了,增加消息體字段和計數字段,用來重發和失敗計數,如果正常,保留原來機制,什麼都不做,如果ack失敗,計數+1,等2秒並重發,如果3次了,報警,人工干預可能是有問題,在這裏也可以先扔死信隊列,我們是人工重新補償。(再看一下建消息表+kafka的弊端,它會在發送成功之後有個刪DB消息表的操作,還要定時任務去把消息表未發送成功狀態的消息讀出來重發,效率慢)
2. (下游系統被消費)網關係統保證操作成功下單才ack隊列。網關係統監聽隊列,採用手動ACK模式,(一定不要拋異常,不要依賴隊列重試,拿不到重試次數,除非想辦法設置),業務記賬塊封裝成可重試執行塊,重試超過3次未知異常失敗(餘額不足不算,比如超時),告警,並Nack該消息,進入死信隊列,待人工處理。

-------------------本地消息表-------------

?工作原理或實現原理?

A 系統在自己本地一個事務裏操作同時,插入一條數據到消息表;
接着 A 系統將這個消息發送到 MQ 中去;
B 系統接收到消息之後,在一個事務裏,往自己本地消息表裏插入一條數據,同時執行其他的業務操作,如果這個消息已經被處理過了,那麼此時這個事務會回滾,這樣保證不會重複處理消息;
B 系統執行成功之後,就會更新自己本地消息表的狀態以及 A 系統消息表的狀態;
如果 B 系統處理失敗了,那麼就不會更新消息表狀態,那麼此時 A 系統會定時掃描自己的消息表,如果有未處理的消息,會再次發送到 MQ 中去,讓 B 再次處理;
這個方案保證了最終一致性,哪怕 B 事務失敗了,但是 A 會不斷重發消息,直到 B 那邊成功爲止。

?的作用或優點或應用場景?

嚴重依賴於數據庫的消息表來管理事務,高併發場景不適合。

?我搭建過,如何搭建?

?搭建和使用過程中遇到哪些問題?

?*與*的區別?

-------------------XA 方案(Jta+Atomikos)-------------

?工作原理或實現原理?

兩段提交:jta+atomikos實現了兩階段提交分佈式事務。一個協調控制多個參與者一起提交完成。適合於單體系統多數據庫的場景。我們微服務都是一個系統一個庫,這個不適合。---可以考慮LCN,自搭一個分佈式協調者系統來管理多個參考者系統。

?的作用或優點或應用場景?

某個系統內部如果出現跨多個庫(但不合規,現在都要求每個服務只能操作自己對應的一個數據庫,通過調用別的服務的接口訪問別人的數據庫

?我搭建過,如何搭建?

?搭建和使用過程中遇到哪些問題?

?*與*的區別?

 

-------------------LCN-------------
?工作原理或實現原理?

全局事物(協調者-LCN服務端管理本地事物(參與者-LCN客戶端

1.LCN客戶端(發起方和參與方都必須要註冊到事務協調者中) 建立一個長連接(和dubbo類似,netty長連接)。
2.發起方調用參與方之前,會向TxManager事務協調者創建一個事務的分組id。
3.發起方調用參與方時,分組id放在請求頭中,傳給參與方。
4.參與方拿到請求頭中分組id,執行完業務後,返回結果響應,自已也會採用假關閉,等待真正提交該事務。
5.發起方收到響應後, 執行事務提交,告知協調者。參與方隨後跟着提交。

訂單服務(發起方)調用庫存服務接口(參與方)之後,如果訂單服務(發起方)執行沒有問題的下,
訂單服務(發起方)使用對應的事務分組id,通知給TxManager事務協調者,讓後TxManager事務協調者在根據該事務分組id,通知給所有的參與方提交事務。

?配合集羣原理?

有兩個地方建立長連接:基目啓動時,通過nginx與新的LCN服務器節點建立長連接;宕機時,再通過nginx的故障轉移與新的LCN服務器節點建立長連接

 

?的作用或優點或應用場景?

?我搭建過,如何搭建?

1.首先通過nginx配置多個tm-lcn協調者負載均衡配置,讓後 LCN客戶端啓動項目的時候訪問nginx負載均衡地址獲取lcn協議通訊IP地址和端口號,並且對該連接保持長連接。 
2.因爲LCN客戶端與TM協調者保持的是長連接,當tm協調者宕機之後,LCN客戶端會立即重新進入到獲取負載均衡地址lcn協議通訊IP地址和端口號。
 

?搭建和使用過程中遇到哪些問題?

問題1:debug調試的時候,發現,發起者事物成功了,參與方事物回滾了,分佈式事物不一致,
解決:後來看源碼是有一個超時機制,參與方在5秒沒有收到協調者通知情況下,會默認執行回滾。調試時可設置增長超時時間

-------------------最大努力通知方案(柔性事務BASE補償幾次)-------------

?工作原理或實現原理?

採用類似支付寶回調機制,但是,要考慮補償機制,重試機制,還要考慮冪等性,重複性問題。

  1. 系統 A 本地事務執行完之後,發送個消息到 MQ;
  2. 這裏會有個專門消費 MQ 的最大努力通知服務,這個服務會消費 MQ 然後寫入數據庫中記錄下來,或者是放入個內存隊列也可以,接着調用系統 B 的接口;
  3. 要是系統 B 執行成功就 ok 了;要是系統 B 執行失敗了,那麼最大努力通知服務就定時嘗試重新調用系統 B,反覆 N 次,最後還是不行就放棄。

?的作用或優點或應用場景?

?我搭建過,如何搭建?

?搭建和使用過程中遇到哪些問題?

?*與*的區別?

------------------2PC與3PC-------------

?二階段提交協議實現爲什麼會有阻塞問題?

2PC:
第一階段 -表決階段(表決階段準備過程)    
第二階段 - 提交階段(執行階段,執行提交過程)
準備過程(請求階段)沒問題提交過程有公共資源同步阻塞問題。執行提交過程中,所有參與節點都是事務阻塞型的。當參與者佔有公共資源時,其他第三方節點訪問公共資源不得不處於阻塞狀態
二階段提交缺點單點故障 由於協調者的重要性,一旦協調者發生故障參與者會一直阻塞下去,尤其在提交階段,參與者鎖定公共資源未釋放

3PC:(改動點---1、協調者和參與者間引入超時機制來解決單點故障問題、超時不再等待減少阻塞;2、插入一個準備階段)
來了解一下三階段提交:(把原來的表決階段分爲詢問和準備階段,詢問只問不要求執行
詢問階段canCommit(預先檢查階段,帶有超時機制):詢問其他參與者,如果有一個返回NO或超時,就回滾事物。(協調者只需要回答能否,而不需要做真正的操作
準備階段(PreCommit準備過程,鎖資源) ,
提交階段(執行階段,執行提交過程)
對比,三階段提交最大優點就是降低了參與者執行階段的阻塞範圍,並且能夠在出現單點故障後繼續達成一致。
缺點就是在去除阻塞的情況下引入了新的問題,那就是準備階段,參與者1接收到消息後執行成功,其他參與者有失敗的,協調者就會向所有參與者發出回滾命令,但此時參與者1(網絡出現問題)接收不到協調者命令,超時之後參與者1一個人提交,和其他參與者不一致問,

2PC和3PC的對比?

2pc的問題:

問題1:阻塞問題,提交階段,協調者單點故障掛了,所有參與者會一直鎖着公共資源不釋放等待協調者命令,就會出現阻塞問題----解決方法:3PC在協調者和參與者間引入超時機制,超時默認提交,當然又有新的不一致問題1
問題1.2:單點故障問題,如上,一個單點故障影響了其他協調者無法再進行工作----
解決方法:如上
問題2:不一致問題,提交階段,協調者和參與者1都掛了,且參與者1是執行了回滾但未通知協調者就掛了。當協調者和參與者1恢復時,假設協調者從其他沒掛掉的參與者處得到了提交成功的反饋,提交了事物。這就和參與者1執行了回滾形成了不一致性。----解決方法:3PC插入一個詢問階段,如果參與者1提交階段會回滾,那其詢問階段也是回滾應答,其他參與者也會回滾,所以是一致性的

3PC的問題:

問題1:超時機制帶來的新的不一致問題,詢問階段全OK,然後進入準備階段,參與者1接收到消息後執行成功,反饋給協調者時超時且中斷了,協調者2PC就有的特點會把這種超時當成失敗發回滾命令,其他參與者都收到了回滾命令,但此時參與者1(網絡出現問題)接收不到協調者命令,超時之後參與者1會根據3pc新增的參與者至協調者超時機制默認一個人提交,就造成和其他參與者不一致問題(這個特性導致的:2pc本身已支持協調者等待參與者超時會回滾

3PC爲什麼比2PC好?

就是上面解決的兩個問題:
1、超時機制(注意是:新增參與者等待協調者超時,2pc本身已支持協調者等待參與者超時會回滾)--解決阻塞問題、單點故障問題
2、插入一個詢問階段---解決協調者和參與者1都掛了的不一致性問題(這個特性導致的:2pc本身已支持協調者等待參與者超時會回滾



 

 

--------MQ削峯填谷-----

示例2-賬務系統內部削峯的同時,如何保證分佈式安全

?賬務如何處理緩衝流量,削峯填谷+分佈式事物的
目的:解決業務定時任務量的削峯填谷;安全一致性(最大化消息不丟);

RabbitMQ解決分佈式事務原理: 採用最終一致性原理。需要保證以下要素

1、冪等性、請求不重複,redis分佈式鎖()
2、確認生產者投遞,一定要將數據投遞到MQ服務器中(採用MQ發送消息確認機制
3、確認MQ消費者消費,消息能夠正確消費,採用手動ACK模式(注意重試冪等性問題,不要依賴隊列重試,走業務代碼重試)
4、死信隊列,消息重試失敗3次,告警,放入死信隊列()
6、通知機制(補償通知機制),
真實項目舉例2:
賬務系統
1.redis分佈式鎖,防止相同訂單併發。然後校驗基本參數,對請求號(還有業務訂單號,如果重複了,隊列消費時校驗批次所有訂單號是否完全冪等,是就成功)下單入庫,初始狀態(要不要先把普通用戶錢夠了或所有形成記賬數據包再扔隊列,最好整體扔隊列安全)。
2. 確認機制保證提交到隊列。把消息發往隊列,這裏做成近似一致性:重寫業務生產者發送消息確認機制,並把CorrelationData 類重寫了,增加消息體字段和計數字段,用來重發和失敗計數,如果正常,保留原來機制,什麼都不做,如果ack失敗,計數+1,等2秒並重發,如果3次了,報警,人工干預(可能是隊列有問題),在這裏先扔死信隊列1(消費失敗也是扔這裏)。(再看一下建消息表+kafka的弊端,它會在發送成功之後有個刪DB消息表的操作,還要定時任務去把消息表未發送成功狀態的消息讀出來重發,效率慢)
3. (下游模塊被消費)賬務系統的消費模塊要保證操作成功記賬才ack隊列。消費模塊監聽隊列,採用手動ACK模式,(一定不要拋異常,不要依賴隊列重試,拿不到重試次數,除非想辦法設置),消費模塊的業務記賬塊封裝成可重試執行塊,代碼重試超過3次未知異常失敗(餘額不足不算,比如超時),就告警,並Nack該消息,進入死信隊列1,待人工處理(業務邏輯有問題或超時3次)。

3.2 另外,成功記賬後得在同事物內,更改請求表狀態爲記賬成功或失敗,(通知狀態和業務狀態是兩字段)
6、通知上層調用方系統。立馬通知一次上層系統,如果通知失敗,進入補償通知機制
7、補償通知機制(延時隊列,間隔性通知)。(首先會提供一個主動查詢請求號是否成功的接口給上層系統用)。
任務調度策略一般設定3s、30s、60s、10分鐘調度多次。
參考自已寫的:面試整理-3-RabbitMQ的  ?RabbitMQ如何實現定時階梯性通知?
 一、選延時隊列來拓展。(建意用)
延時隊列本身是沒有消費者的(直拉拒絕的意思),設置TTL放進去之後,需要將其DLX綁定到其他普通隊列2隊列2監聽,隊列1的時間到之後,隊列2就會收到消息,然後通知一次,若失敗重置TTL到期(生存)時間,假設當前3秒,那重新發布一條60秒進延時隊列。如此3秒,60秒,10分,執行到10分這次停止,我就不再重放隊列了。等業務人工補償,郵件告警

參考 :https://blog.csdn.net/skiof007/article/details/80914318

此處用方法1的延時隊列,修改header裏面的Map參數值:
original-expiration這個字段表示消息在原來隊列中的過期時間,根據這個值來確定下一次通知的延遲時間應該是多少秒。
x-dead-letter-exchange

同步的批量交易接口超時嚴重(保留同步冪等的情況下,改用異步通知,異步的好處:1.支付結果更準確安全2.用服務器接收可以在後續做各種業務邏輯。異步機制:0重試一次,1,30,2小時,10小時,次數存redis)
 

最後實現一個系統模式:接口同步返回受理成功,異步通知+主動補償查詢的補償機制。

 

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