首頁>技術>

1. 最終一致性

1.1 本地事務表 + 輪詢補償

互動流程

commit DB事務提交階段 本地客戶端向DB進行事務提交,此時需要將業務資料和記錄訊息事務狀態的資訊表同時實現本地事務,此時標記訊息事務狀態為UN_SEND未傳送或未完成狀態,此時MQ未傳送② ack DB確認階段 返回DB事務提交成功或失敗狀態③ commit MQ事務提交階段 客戶端發起MQ傳送請求④ update 本地事務表更新階段 根據MQ傳送結果進行本地訊息事務表狀態更新,成功則更新為SEND傳送成功或傳送完畢⑤ MQ補償 本地訊息事務表定時輪詢 對未傳送成功訊息事務進行補償傳送,實現分散式事務的最終一致

場景:重構業務新老系統雙寫庫同步

專案背景

這是一個重構系統新老系統同時服役切量遷移的業務場景,老系統正在線上服役為各業務方提供介面查詢功能,新系統重構完成後需要對接接入,呼叫流量要陸續從老系統切換到新系統,最終老系統迭代下線。

分散式事務

需要解決的分散式事務問題就是,雙系統的資料是異構、分散的,線上不可停量,需要陸續切換完成,因此需要事先將老庫存量資料洗入新庫,此過程中增量資料寫入是存在的,但是最終新老庫是相對一致和統一的,該場景需要解決的是資料雙庫的雙寫問題

設計方案

場景Q&A

Q:如何保證雙庫雙寫? A: 同步寫辛庫,MQ非同步寫老庫 本地事務 + 訊息事務表業務資料持久化開啟資料庫本地事務,該事務中記錄業務資料和同步狀態資訊 確保本地事務一定成功,不保證非同步MQ事務資料庫事務成功後再發送寫老庫的MQ,保證本地事務一定完成才會觸發MQ傳送,這樣確保本地事務一定成功,MQ可能成功也可能失敗 重試MQ事務狀態,最終一致如果MQ事務失敗,透過定時任務輪詢進行重發驅動,最終一致Q:非同步MQ寫,延遲問題如何解決? A: 增加冗餘查詢增加冗餘對另一庫的冗餘查詢進行Double Check。由於呼叫方几乎不可能同時使用新老系統做業務,因此延遲時間取決於MQ非同步消費寫的速度,如果場景比較複雜要確保絕對一致可以增加該處理方式Q:雙寫過程中多個MQ如何保證順序、防重等問題? A: 業務時間 + 業務ID (1)同一個業務ID代表一個同一筆業務,可以依此進行業務防重處理 訊息業務ID業務時間消費時間處理邏輯IDTT執行IDTT+1防重不處理 (2)同一個業務ID的基礎上增加業務時間,可以依此保證業務資料的實時重新整理 業務時間、消費時間同序 訊息業務ID業務時間消費時間處理邏輯IDTT執行IDT+1T+1執行(覆蓋) 業務時間、消費時間亂序 訊息業務ID業務時間消費時間處理邏輯IDTT+1拋棄(業務時間較早)IDT+1T執行 (3)不同業務ID的基礎上增加業務時間,可以依此保證不同業務資料的按照業務時間重新整理 訊息業務ID業務時間消費時間處理邏輯IDT+1T+1執行(業務時間較新)ID+XTT拋棄(業務時間較早)

場景:第三方認證核驗

專案背景

這是一個認證系統以來外部核驗系統進行使用者身份鑑權的場景,即認證系統記錄認證發起記錄,並請求到外部的核驗系統發起一筆核驗請求,使用者在核驗系統確認後核驗結果返回到認證系統確認使用者的真實資料狀態。

分散式事務

該流程中認證系統是一個本地系統,存放使用者發起的認證流水資訊和核驗狀態,依賴外部核驗系統返回該筆認證記錄的核驗狀態,由於核驗過程是非同步的,使用者可以選擇任意時間完成或者永遠不完成,需要保證每次認證流程只有一筆業務發起,而且需要根據業務時間進行核驗流程的超時進行強制取消或者補償查詢對齊核驗狀態等,需要解決的分散式事務是認證流水、核驗結果的一致性

設計方案

正向流程補償流程

場景Q&A

Q:本地事務認證流水成功了,外部核驗系統提交失敗了怎麼辦? A:透過定時任務補償觸發二次提交,只要外部事物提交一直處於未成功,便一直會被重試提交,直到成功Q:外部核驗系統事務完成了,本地事務認證流水提前被作廢了怎麼辦? A:以本地事務認證流水的結果為準。本地事務是透過定時任務進行補充提交+外部事務狀態核驗查詢的,即時在臨界點外部事務完成了,但是超過了業務處理時間已經關閉,不會再補充修改,這也是根據業務場景做的取捨,使用者可以再次發起新流程進行核驗

1.2 本地事務表 + 事務訊息

互動流程

prepare 準備階段 本地客戶端向DB、MQ傳送prepare請求② ack 準備確認階段 DB、MQ作為事務參與者返回本地客戶端ack確認③ commit/rollback 提交/回滾階段 根據事務參與者在準備確認階段返回結果進行事務提交或回滾,此時一旦有事務參與者返回異常或超時未返回則進行回滾提交④ callback 補償回調階段 當事務超時提交時,則由MQ進行回撥查詢資料庫本地事務情況⑤ commit/rollback 提交/回滾階段 根據補償回調階段進行事務提交和回滾,實現分散式事務的最終一致性

場景:分庫分表路由欄位繫結

專案背景

該業務是在分庫分表場景下,需要一個切分鍵欄位進行資料分片路由,一般我們ToC業務的話會使用userId這樣的欄位進行切分。然而水平切分資料帶來了資料庫讀寫效能的同時也存在一個問題,那就是查詢必須攜帶切分鍵才可以完成,因為要依賴它進行資料路由查詢,比如在以userId進行資料路由切分時,如果想按照使用者的身份證、姓名等進行匹配查詢是無法實現的,因為我們事先是不知道userId、身份證、姓名的等值匹配關係。一般而言,我們可以透過HBase + ES的方案進行解決,即監聽不同庫的binlog日誌,將其按照時間進行排序切分匯入HBase表中,加入要檢索的索引到ES中解決分庫分表下資料切片產生的聚合問題。

分散式事務

基於以上場景,除了透過HBase+ES實現之外,還可以透過切分鍵與非切分鍵進行資料繫結解決,但是由於切分鍵與非切分鍵的路由一般不一致,資料會分散到不同庫,因此無法做本地事務,這是我們需要解決的分散式事務問題。

設計方案

互動流程

場景Q&A

Q:非同步MQ寫有延遲,查不到切分鍵如何處理? A:事務處理開始階段透過Redis記錄事務開啟的分散式鎖標識,當其他存在衝突的同業務在該事務的處理過程有查詢時,透過判斷分散式鎖標識是否存在來判斷事務的開啟,若存在則非同步等待併發起間隔查詢直到事務超時,若事務超時週期內反覆查詢到則返回,否則根據事務處理後結果返回Q:本地事務與MQ事務是如何協作的? A:相當於兩個2PC事務協作。 1.一階段DB、MQ同時prepare(並行) 2.二階段DB先commit,成功後MQ再commit(序列) 流程階段操作Ack反饋持久化是否結束分散式事務成功正向流程PrepareDB prepare MQ prepareYesNoNoNo正向流程CommitDB commit MQ commitYesYesYesYes------異常流程PrepareDB 或 MQ 異常NoNoYesNo異常流程CommitDB提交異常NoNoYesNo異常流程CommitMQ提交超時 回撥本地事務狀態,本地事務成功則提交MQ事務YesYesYesYes異常流程CommitMQ提交超時 回撥本地事務狀態,本地事務失敗則取消MQ事務YesNoYesNoQ:會不會存在MQ事務成功,本地事務失敗? A:不會,而且要避免這種情況發生。兩個2PC事務的prepare準備階段可以同時發起,但在commit提交階段要先保證本地資料庫事務成功之後再進行MQ事務訊息的commit,也就是在commit階段是存在依賴關係、序列化之行的Q:事務訊息如何確保最終一致? A:prepare階段失敗、本地事務commit階段則均不會持久化;當prepare階段成功、本地事務commit成功,此時MQ的commit階段異常,則依賴MQ事務訊息的超時commit機制觸發回撥本地事務狀態介面方法來決定MQ的二階段是commit還是cancel

1.3 TCC(Try-Commit-Cancel)

互動流程

TCC事務其實主要包含兩個階段:Try階段、Confirm/Cancel階段。

try-嘗試執行業務完成所有業務檢查(一致性)預留必須業務資源(準隔離性)② confirm-確認執行業務真正執行業務不作任何業務檢查只使用Try階段預留的業務資源Confirm操作必須保證冪等性③ cancel-取消執行業務釋放Try階段預留的業務資源Cancel操作必須保證冪等性

從TCC的邏輯模型上我們可以看到,TCC的核心思想是,Try階段檢查並預留資源,確保在Confirm階段有資源可用,這樣可以最大程度的確保Confirm階段能夠執行成功。這裡的資源可以是DB,或者MQ,RPC,只要是分散式環境中的事務載體就可以,而且需要這些分散式事務的參與者具備正逆向條件,比如DB、MQ的事務可以支援2PC,可以根據協調者對其進行事務提交或者取消操作,RPC比如賬戶服務可以支援正向增加也可以支援逆向減少,除此之外,DB、MQ要自身支援事務的ACID,這是參與分散式事務的原子性保證,RPC底層也是DB,這裡可以等同理解。以上參與者具備參與分散式事務的基本條件後便可以進行整合和使用,業務流程的驅動和事務的完整性由中間協調者來操作和推進。

場景:積分商品兌換

專案背景

這是一個電商系統比較經典的下單、扣款、發貨流程,在下單之前會透過一系列商品在架狀態、庫存數量、購買限制等有效性過濾,然後在業務系統中進行一個商品兌換的場景。

分散式事務

由於是商品兌換,對於使用者和系統本身來說是這個過程一個原子性的、一鍵完成的操作,因此下單+動賬+發貨是一個現實存在的分散式事務。這裡假設訂單資料和動賬資料在一個本地資料庫事務中,持久化開啟資料庫本地事務,該事務中記錄訂單生成資料和動賬資料資訊,以及發貨狀態的資訊記錄。這裡需要解決的分散式事務是訂單資料、動賬資料、發貨狀態三種的最終一致

設計方案

正向流程補償流程

場景Q&A

Q:動賬扣款成功,但是發貨失敗怎麼辦? A: 定時任務根據發貨狀態進行發貨流程驅動 定時任務補償再次發貨發貨成功則分散式事務最終一致,下游發貨系統進行發貨防重處理 發貨失敗進入逆向流程定時任務驅動發貨最終一致理論上可以一直進行,但是發貨可能有一個流程時效和庫存售罄的問題,可以根據業務場景進行配置比如2天內重複呼叫失敗或呼叫返回無庫存則進入逆向關單退款流程使得分散式事務恢復成最開始的一致性狀態Q:逆向流程回滾賬戶扣款,怎麼防重? A:賬戶流水錶做唯一索引正逆向型別 + 業務ID,和賬戶額度表進行本地事務操作,確保只能成功一筆正向/逆向業務操作

場景:廣告任務結算

專案背景

當一個App有了足夠多的使用者體量,便開始有商家進行廣告或商品的投放,平臺透過包裝運營活動、廣告位等,將使用者曝光與商家付費結合達到流量變現的目的。

分散式事務

當用戶進行瀏覽、關注、商品購買、影片觀看、App下載等多種任務,我們會根據商家配置等付費規則進行商家廣告費用的扣減,同時還要為使用者完成任務進行獎勵結算,此時的分散式事務便是商家賬戶扣減與使用者賬戶增加的資料一致性問題

設計方案

互動流程補償流程

場景Q&A

Q:商戶扣款失敗或者商戶扣款成功,使用者結算失敗怎麼辦? A: 定時任務根據結算狀態進行結算流程驅動,會一直輪詢補償嘗試結算使用者,直到成功。Q:商戶扣款成功,使用者結算失敗為何不進行做業務超時的逆向流程回滾商家扣款? A: 使用者做任務時一定是做了前置校驗進行平臺任務發放的,也就是說使用者任務只要完成必須要進行結算,這是一個不能逆向的流程。即使極端情況下商戶餘額空了暫時無法結算到使用者也要一直重試,一旦商戶餘額充足則繼續整個結算流程。

場景:運營活動抽獎

專案背景

抽獎是運營活動中比較常見的方式,對於使用者來說需要做的是參加設定人物獲取積分,攢夠積分就可以開始抽獎,抽中後即等待獎品入賬,一般券會立刻入賬使用,而實物商品則需要耐心等待物流送到使用者手上。

分散式事務

關於抽獎,涉及賬戶動賬、庫存參與次數扣減、抽獎等多個環節,該場景要解決的分散式事務是賬戶動賬、活動庫存變更、抽獎下單資料一致性

設計方案

互動流程補償流程

場景Q&A

Q:動賬扣減失敗,補償流程為何不驅動扣減完成抽獎? A: 抽獎業務對於使用者來說實時性要求很高,正向流程沒有完成的話,沒有透過補償流程驅動的必要性了,使用者體驗不好容易產生問題,補償流程只針對賬戶扣減成功扣沒有順利完成抽獎的情況進行賬戶補款即可。而且這部分補款是有延遲的,在C端展示可以最佳化或者忽略合併掉,保證的是賬戶額度無損。2. 弱一致性

2.1 最大努力通知 + 訊息重試控制

場景:資料變更同步下游業務方

專案背景

系統資料發生變更時,會對外部系統產生一定影響,外部系統需要知道這種資料變化,這便是資料狀態同步的場景。一般來說資料互動可以有推(Push)、拉(Pull) 兩種形式,這裡先說推模式,即資料變更方負責將變化通知到資料關注方。

分散式事務

這裡要保證的是資料變更在多個應用中的狀態一致

設計方案

互動流程

場景Q&A

這裡是弱一致性的實現,沒有做本地事務表和定時任務輪詢對比各事務狀態進行補償操作。完全依賴於MQ的失敗重試驅動,若RPC呼叫失敗即資料同步業務方失敗,MQ會一直進行重試操作,隨著重試次數增加,重試間隔也會增加,這裡也可以業務自行進行最大努力嘗試次數的控制,超過多少次嘗試仍失敗則放棄,因此不能保證最終一致

場景:資料變更廣播下游業務方

專案背景

這裡是資料同步的說拉模式,即資料關注方對資料變更方進行資料狀態變更的監聽,這種處理方式處理的主動權在於資料關注方,資料變更方只負責和保證一定通知到資料變更情況,是否能夠同步成功則由監聽方處理和相容。

分散式事務

這裡要保證的是資料變更在多個應用中的狀態一致

設計方案

互動流程

場景Q&A

這裡也是弱一致性的實現,沒有做本地事務表和定時任務輪詢對比各事務狀態進行補償操作。完全依賴於MQ消費方的處理,若消費方處理失敗或在訊息佇列規定時間內沒有消費完畢,則資料無法保證最終一致

2.2 戰略放棄 + 報警 + 人工修復

場景:秒殺庫存回滾

專案背景

在秒殺場景中,最複雜的除了解決高併發問題外,最核心的就是活動商品的庫存控制、變更問題,一般商品庫存會初始化到Redis快取中進行管理,秒殺方法會對Redis快取庫存數量進行校驗、扣減操作,透過MQ非同步扣減DB庫存,既利用Reids原子操作進行庫存數量操作,又利用快取抗住高併發請求,起到非同步削峰的作用,這是秒殺的正向流程。而逆向流程是使用者秒殺到商品預佔了庫存,但是沒有及時進行訂單支付或者進行了訂單取消,此時要發起對庫存的恢復操作。

分散式事務

這裡的分散式事務是Redis快取庫存與DB庫存數量一致性問題

設計方案

互動流程

場景Q&A

Q:秒殺場景會出現哪些分散式問題? A: 根據如上流程圖,扣減快取庫存、建立訂單、非同步MQ傳送是在一個同步的函式方法中的三個非原子的子步驟,而秒殺場景下流量洪峰會一瞬間打滿執行緒,以上三個子步驟任何非同步都會出現問題,因為都是先扣快取庫存數量,根據實踐經驗看,極端情況下會出現扣減快取庫存成功了,後面建立訂單失敗了或者非同步MQ沒有發出來無法削減DB庫存數量,因此資料結果是快取庫存扣減的多,DB扣減的少,實際搶購賣出的少,換句話說就是出現了少賣的現象。Q:會不會出現超賣現象? A: 不會。依賴於Redis單執行緒命令執行的保證。這裡需要注意的是讀、寫命令不是一致,可以結合分散式鎖實現,也可以透過Lua指令碼實現命令的原子性執行。

這裡也是一個弱一致性的實現,業務場景我們保證不超賣即可,對於極端情況出現的庫存數量無效多扣減做戰略性放棄,一般情況下不會影響大多業務使用,如果非要吹毛求疵達到賬戶金額那種強一致性,思路也很簡單,可以藉助定時任務輪詢對比快取與DB庫存數量進行校驗,這裡還要考慮到其他在行流程如超市關單庫存恢復,仍然在行的秒殺活動等,保證資料處理不多加不多減。

3. 總結

3.1 分散式角色

參與者可以通俗的認為是DB、RPC、MQ這些能夠提供事務能力的中介軟體或介面服務協調者維繫分散式事務各個參與者分散式狀態的系統、中介軟體,如Zookeeper、業務系統

3.2 技術保證

資料庫事務 資料庫如MYSQL提供了2PC、XA協議,依賴於WAL + Redo Log + 刷盤策略保證MQ事務 提供了2PC協議,依賴於Ack機制+刷盤策略保證

3.2 強弱一致選擇

強一致性強一致性確保的不是事務一定成功,而是事務參與者的子事務要麼全成功,要麼全失敗,保證子事務的最終一致。一般依賴於定時任務、補償機制、Double Check等方式進行事務狀態的校準和協調,一般設計和實現的複雜度大,參與者越多,流程越複雜,越難以維護,最終一致的延遲性和可靠性保證越難弱一致性弱一致性放棄了最終一致性的保證,透過最大努力實現而不保證最終的結果,這種場景減少和減低了開發和設計的複雜度

3.3 冪等&防重

業務冪等通常會定義bizId代表全域性唯一的業務標識。在MQ重發、重複消費、亂序,RPC重複呼叫等場景進行業務防重相容處理。如賬戶餘額的強一致防重處理,可以結合流水錶唯一索引正逆向型別 + 業務ID進行攔截一般大多依賴於資料庫的唯一索引進行防重保證,如果擔心資料庫效能問題,可以前置快取攔截處理

3.4 儘早干預&補償一致

儘早干預

指的是程式碼邏輯上儘早對序列處理的做個子事務進行回滾或逆向操作,這樣可以儘快結束分散式事務,而不需要等待相對更為延遲的定時任務或其他補償機制來驅動,這裡可以使用旁路方法或不阻塞主方法放到MQ或非同步執行緒中進行處理,比如秒殺下單發貨因為庫存不足或商品下架可以立刻進行發起關單退款的逆向流程

補償一致

補償機制一般可以透過定時任務、MQ重試來進行子事務驅動整個分散式事務的完結

8
最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 線上教室 iOS 端聲音問題綜合解決方案