異構交易場景交互流程及一致性保證

問題如下:

A系統聯機同步調用B系統(A和B不是同一公司系統,不能用分佈式事務),

如何保證系統間數據準實時一致性(聊聊設計思路即可)?

提醒:需要考慮調用超時、併發、冪等、反交易先到等。

各種異常場景怎麼處理要考慮更完善些,如事務隔離、併發、反交易先到調用方和服務方約定(前端客戶不可能一直等着)

這種聊思路的問題,往往問的都很大,或者說比較唬人,實際上遇到這種問題,我們要做的就是抽象。

抽象出場景,抽象出問題的核心要點。

我們能夠提煉出要點,非同一公司系統(跨網絡,異構)、反交易先到(我們基本能確定提問者大概想知道的思路與交易有關)、服務方預定,前端客戶不可能一直等待(交易流程往往是長事務流程,不能簡單依靠單個接口調用,基本上是異步流程)。

有了這些前提,我們就可以基本抽象出討論的背景和模型:

模型與背景提煉

因爲前提是A、B系統分屬不同的公司,也就是說A B系統是通過公網進行交互的兩套異構系統,極有可能實現的技術棧也各不相同,因此互相之間只能通過暴露在外的接口進行交互,我們就認爲是通過http接口進行的交互。

由於是A系統調用B系統,因此我們可以抽象爲點對點的消息通信場景,其中A爲主動拉取方,B爲被拉取方。

問題提到說,我們說不能用分佈式事務,其實是在說不能使用強一致/類2PC的事務實現,如2PC、3PC、SEATA等,但是可以利用諸如最大努力通知的柔性方式進行數據的同步。

關於最大努力通知方案,筆者之前的一篇文章已經有過詳細的討論

有了方案,我們接着抽象出 交易單 這個模型,併爲其指定狀態機:

  1. 交易單創建時,狀態爲 初始化
  2. A系統向B系統發送交易單時改爲, 處理中
  3. 如果B系統同步響應收單失敗,則A系統修改狀態爲 失敗
  4. 同步B系統同步響應收單成功,則A系統修改狀態爲 已提單
  5. 當B系統處理交易完成,通知A系統交易完成,則A系統修改交易單狀態爲 成功,(此處的成功爲真實成功,因爲已經發生了資金扣除/積分等標的物的消耗)
  6. 當B系統處理交易失敗,則通知A系統交易失敗,則A系統修改交易單狀態爲 失敗 (此時的失敗假定爲B系統在扣錢之前就失敗)

超時處理方式

我們討論一下提單請求發生超時應當如何處理。

A系統的出口網關向B系統的入口網關發起提單請求,這是一個同步通信,對於同步請求的失敗(如:簽名失敗,參數異常失敗等),A系統可以發起重試,此時這種請求屬於真實的失敗,因爲壓根沒有發起交易行爲,所以原則上數據是一致的,對於資金而言就是沒有發生扣減等行爲。

掉單查詢

如果A系統提交提單請求超時,此時未能收到B系統回覆的同步 收單成功 的響應,則這時候就存在數據不一致的情況。這個場景就是所謂的 掉單,則A系統需要對掉單的數據(狀態爲處理中)發起掉單查詢操作,思路就是定時發起查詢,獲取B系統對交易單的處理情況。

一般而言B系統都會通知A系統發起掉單查詢的建議時間,如發起交易單10分鐘後即可有處理的確定結果,那麼A系統就可以對已提交10分鐘以上,狀態爲 處理中 的交易單發起掉單查詢。也就是說,10分鐘後,這類中間態的數據,AB系統間可以達成一致。

特別的,如果一次掉單查詢沒能查到確定的結果,則可以設置下一次繼續查詢,這裏推薦採用 時間衰減策略 進行查詢,這是交易場景乃至中間件中常用的一種未知數據定時同步的通用思路。

結果通知

對於交易場景,處於對數據實時性的考慮,我們常常希望下游系統處理完數據之後能夠及時通知我們結果。

在這個場景中就是A系統需要對接B系統的 交易結果實時通知接口,當交易單被B系統處理完成之後,B系統會對交易單處理結果發起通知,及時回調A系統處理的結果。此時,A系統成爲被調用方,B系統爲調用方,相比於掉單查詢,結果通知幾乎是準實時的,從B系統發起通知到A系統接收到通知往往都在百毫秒級別(支付寶支付結果通知能夠達到數十毫秒)。

簡單總結下,對於超時的處理,我們就是通過掉單查詢和實時通知方式,通過主動輪詢處理結果與被動接受結果通知的方式,通過推拉結合的方式共同保證AB系統之間的數據達成最終一致。

併發提單

對於併發提單而言,其實屬於老生常談類的話題。其本質在於分佈式場景下請求的防重放處理思路。

核心就在於請求串行化,我們往往通過CAS、加鎖等方式進行處理。

具體到具體的實現細節,CAS方式有數據庫狀態標識(狀態機)、加鎖方式其實就是分佈式鎖,簡單的說就是通過分佈式鎖方式進行處理,通過對一筆交易單加分佈式鎖,獲取分佈式鎖成功的請求才能發起請求,發起請求後寫入冪等記錄,完成請求後釋放鎖,防止併發提交。

冪等思路

關於冪等,展開說可以單獨寫一篇文章,那麼擇日不如狀態,我們下一篇文章就聊聊冪等處理的那些常用姿勢。

這裏爲了解答問題,我們說說主要思路,對於細節就不展開了,懂的同學們應該能夠很快的心領神會,不懂的也沒關係,我們下篇文章就會對冪等進行詳細的展開。

對於冪等而言,我們通常需要通過冪等校驗來進行,比如:

高併發場景下,將冪等標識寫入Redis緩存,用於對寫請求冪等 或者請求如果量不大,則通過數據庫唯一約束進行冪等處理,保證只有一筆交易單落庫(如唯一約束 訂單號),唯一約束是最後一道防線,用於對寫請求冪等 低併發場景下,通過先查詢,後插入(更新)的方式也可以進行冪等校驗,但是高併發場景下會有重複更新/新增的風險,因此往往需要配合分佈式鎖共同作用,將併發請求串行化 單單就冪等來說,查詢天然冪等,更新則可以通過上面的方式進行冪等保證。具體的細節我們後續文章專門講解。

反交易先到

首先明確何爲“反交易”,反交易,顧名思義,反向交易,我們舉個例子就好懂了。

比如說,扣款的反交易,就是衝正(比如說,轉賬操作,扣除A的錢,給B加錢失敗。則A扣除的錢需要補回,這個過程就是衝正。實際的衝正涵蓋的範圍更廣,我們只需要簡單認爲是扣款的反向操作,但是要區別於提現和充值。)

比如說,A系統請求對交易單支付100元,B系統扣款成功後向A系統返回支付成功的通知消息;此時B系統後續操作故障,導致該交易無法繼續進行下去,則B系統對A系統扣除的100元執行了衝正之後,通知A系統交易已衝正退單。

所謂反交易先到,就是說網絡發生擁塞,導致衝正退單的消息,先於支付成功的消息先到了。

我們的A系統的交易單不是有狀態機麼,狀態機就是處理反交易先到的利器。

我們要求對於交易的處理是串行的,如何串行,其實簡單的說,通過狀態機就能很好地實現。

當然要說明的一點是,對於實際情況,需要具體業務具體分析,對於我們當前討論的場景而言,我們通過狀態機能夠解決問題,具體過程如下,

我們假定,A系統的交易單的狀態機只能按照 處理中->支付成功->退單 這個流程進行流轉,當退單先於支付成功到達時,我們需要在一個事務中同時完成流水的插入,交易單狀態的更新。對於更新操作而言,我們的sql期望如下

update order set order_status=退單 where order_status=支付成功 and order_id=xxxxx

由於狀態機只允許固定的訂單狀態遷移,我們在更新狀態的時候帶上老狀態,實際上當前的order_status=處理中,因此update失敗。最終處理爲通知處理失敗,A系統告知B系統對該通知進行重發。那麼B系統就只能老老實實的重新發起通知,這也是一個合格的交易系統所必須具備的能力。否則你的系統不支持通知重複發起,用戶體驗也太差了。

此時由於狀態機的原因,交易單狀態還是處理中,當被擁塞的支付成功的通知到達,交易單狀態成功更新爲 支付成功 此時執行的update語句爲

update order set order_status=支付成功 where order_status=處理中 and order_id=xxxxx

後續重試的 退單通知(所謂的反交易)到達後,交易單根據狀態機便能夠成功進行流轉,具體的update語句如下:

update order set order_status=退單 where order_status=支付成功 and order_id=xxxxx

從我們的分析看出,只要有狀態機存在,無論如何,交易單的狀態只能按照 處理中->支付成功->退單 這個方式流轉而不會發生狀態的躍遷跳躍。

所以我們說,狀態機,就是系統間處理反交易先到的利器,狀態機也是交易類系統通用的神兵利器。

前端用戶不能一直等待處理思路

還有一點就是前端客戶不可能一直等着,實際上在上述的過程中我們已經解答了這個問題。

我們本次分析問題採用整體的方案是基於最大努力通知的思路,核心的步驟就是 同步提單,掉單查詢,結果通知。通過對這幾個步驟進行結合,我們就能夠避免前端一直等待,因爲交易屬於一個長事務業務,上游/前端只需要提交成功就可以去幹別的事情了,剩下的複雜操作讓下游系統慢慢處理,這其實就是體現了異步的思維。

通過對賬保障數據一致性

最後還要提一下,對於交易系統而言,數據一致性保證的兜底方案就是對賬機制,關於對賬,我在近期也會單獨寫一篇文章進行詳細討論(又一個flag)。

交易系統通常具備t+1的對賬,簡單的說就是,每天生成前一天的對賬單,在我們的這個場景中,A系統每天都向B系統請求自己前一天的交易對賬單,下載到本地,通過A系統自己的渠道流水號/交易單號,與B系統提供的交易單進行逐條的對賬,這個過程往往能夠通過定時任務來自動化的執行,把不一致的交易單對平。從而將兩個系統之間的數據達成最終一致,比如說,A系統沒收到B系統的通知,掉單查詢也沒有查到的交易單,往往最終通過對賬都能夠獲取到數據的最終狀態。

小結

本文,我們針對一個問題,給出了交易場景中常見的數據一致性的保障思路,並通過場景提煉,介紹了交易類場景設計過程中需要注意的思路,希望能夠對讀者朋友們有所幫助。

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