pos機(jī)退款需要先支付嗎,基于有限狀態(tài)機(jī)與消息隊(duì)列的三方支付系統(tǒng)補(bǔ)單實(shí)踐

 新聞資訊  |   2023-05-20 09:35  |  投稿人:pos機(jī)之家

網(wǎng)上有很多關(guān)于pos機(jī)退款需要先支付嗎,基于有限狀態(tài)機(jī)與消息隊(duì)列的三方支付系統(tǒng)補(bǔ)單實(shí)踐的知識(shí),也有很多人為大家解答關(guān)于pos機(jī)退款需要先支付嗎的問(wèn)題,今天pos機(jī)之家(m.afbey.com)為大家整理了關(guān)于這方面的知識(shí),讓我們一起來(lái)看下吧!

本文目錄一覽:

1、pos機(jī)退款需要先支付嗎

pos機(jī)退款需要先支付嗎

0.引言

在日常生活中,從線下的超市購(gòu)物到線上的外賣點(diǎn)餐、電商網(wǎng)購(gòu)等,支付無(wú)時(shí)無(wú)刻不在發(fā)生,不論是通過(guò)現(xiàn)金、pos 機(jī)刷卡還是微信支付寶等第三方支付。線上支付有著及時(shí)便捷一氣呵成的極致體驗(yàn),當(dāng)然也有少數(shù)的時(shí)候體驗(yàn)不夠絲滑,比如早期我們?cè)?PC 版 12306 買火車票,當(dāng)支付完成后,訂單的支付狀態(tài)卻經(jīng)常不能及時(shí)更新,會(huì)有一段時(shí)間的延遲,有時(shí)甚至?xí)却荛L(zhǎng)時(shí)間處在未支付狀態(tài)。

在支付的過(guò)程中由于各種各樣的原因(比如外部渠道處理出了問(wèn)題,異步回調(diào)遲遲不來(lái))導(dǎo)致流程走了一半停了下來(lái),用戶看到訂單依然是未支付狀態(tài),會(huì)不知所措,此時(shí)就需要一種機(jī)制來(lái)推動(dòng)完成這筆交易。本文就以三方支付系統(tǒng)中的補(bǔ)單機(jī)制為例,來(lái)介紹一種較為通用的單據(jù)補(bǔ)償模式。

1.三方支付系統(tǒng)簡(jiǎn)介1.1 什么是三方支付

所謂第三方支付,就是和各大銀行簽約,獨(dú)立于商戶和銀行,具備一定實(shí)力和信譽(yù)保障的,為商戶與消費(fèi)者提供支付結(jié)算服務(wù)的第三方獨(dú)立機(jī)構(gòu)。它是處于買方和賣方之間具備公信力的第三方,承擔(dān)擔(dān)保人和資金托管人的角色。三方支付也可以稱為虛擬賬戶支付,由消費(fèi)者在第三方支付機(jī)構(gòu)開(kāi)設(shè)虛擬賬戶,并用虛擬賬戶中的資金進(jìn)行支付。業(yè)界常見(jiàn)的三方支付有支付寶、微信支付、美團(tuán)支付、京東支付等等。

1.2 三方支付中的交易&支付系統(tǒng)

交易是什么,最直觀的描述就是“一手交錢、一手交貨” ,交易會(huì)使買賣雙方形成債權(quán)和債務(wù)關(guān)系。交易的存在是支付發(fā)生的前提,用戶通過(guò)使用某種支付方式去完成交易。交易是支付流程的驅(qū)動(dòng)者,根據(jù)具體場(chǎng)景組合不同的支付指令,來(lái)完成交易資金的轉(zhuǎn)移。

支付是交易處理資金流的工具,目的是清償債權(quán)和債務(wù)關(guān)系;支持多種支付方式(如銀行卡支付、余額支付、優(yōu)惠券組合支付、類似花唄的信用支付等),負(fù)責(zé)對(duì)接賬務(wù)、會(huì)計(jì)、計(jì)費(fèi)系統(tǒng)等資金處理能力,接收支付指令,驅(qū)動(dòng)完成資金交換。將實(shí)際的支付行為(實(shí)際資金)與內(nèi)部的記賬(虛擬資金)相結(jié)合,保證虛實(shí)一致。

三方支付整體業(yè)務(wù)架構(gòu)如圖 1 所示,其中交易核心與支付核心在業(yè)務(wù)劃分上處于"收單支付域",具備普通交易的收款、付款、退款及充值、轉(zhuǎn)賬與提現(xiàn)等常見(jiàn)功能,還包括了支撐電商業(yè)務(wù)的合單支付、擔(dān)保與分賬的能力。其中交易與支付核心都有一個(gè)異常查補(bǔ)模塊,它囊括了所有業(yè)務(wù)的補(bǔ)償流程,也是本文主要介紹的部分。

圖 1. 三方支付業(yè)務(wù)架構(gòu)

2.什么是補(bǔ)單&為什么需要補(bǔ)單

一筆交易在支付過(guò)程中由于鏈路中的各種異常而中斷,此時(shí)的交易處在一種中間狀態(tài),這種情況俗稱"卡單",即卡在那里不動(dòng)了,沒(méi)有繼續(xù)向下推進(jìn)。還有一種情形,支付核心向渠道發(fā)起了扣款,渠道受理后,銀行卡扣款成功,但由于種種原因沒(méi)有向支付核心發(fā)起回調(diào),導(dǎo)致這筆支付沒(méi)有完成,用戶沒(méi)有享受到相應(yīng)權(quán)益,但銀行卡的錢已經(jīng)扣了,這種情況稱為“掉單”。

不管是卡單還是掉單,都是處在中間態(tài)的訂單。補(bǔ)單就是將處在中間態(tài)的訂單進(jìn)行補(bǔ)償,直到推進(jìn)到終態(tài)(成功或失?。?/strong>。補(bǔ)單一般有兩個(gè)關(guān)鍵點(diǎn),一個(gè)是補(bǔ)償?shù)挠行?,極端情況下可能補(bǔ)償多次都不成功,不能就此放棄了,需要有兜底的機(jī)制;另一個(gè)是補(bǔ)償?shù)募皶r(shí)性,因?yàn)榻灰讙炱鸬臅r(shí)間越長(zhǎng),用戶的體驗(yàn)越差。

交易核心和支付核心的補(bǔ)單相得益彰,具有一定相似程度的設(shè)計(jì)與實(shí)現(xiàn),我們就以支付核心的補(bǔ)單為例介紹下異常補(bǔ)單機(jī)制。

3.補(bǔ)單是如何實(shí)現(xiàn)的

本章首先了解一下業(yè)務(wù)流程,說(shuō)明一下實(shí)現(xiàn)補(bǔ)單需要的前提基礎(chǔ),然后介紹一下補(bǔ)單機(jī)制的演進(jìn)路線,每個(gè)版本存在的問(wèn)題以及在下一個(gè)版本是如何解決的。

3.1 有限狀態(tài)機(jī)與冪等性標(biāo)識(shí)資金操作的有限狀態(tài)機(jī)

我們首先以用戶發(fā)起一筆余額提現(xiàn)為例,說(shuō)明下業(yè)務(wù)流程,簡(jiǎn)化后如圖 2 所示。

圖 2. 余額提現(xiàn)流程

首先生成支付訂單,然后請(qǐng)求賬務(wù)系統(tǒng),扣減用戶賬戶下的余額,接著向外部渠道發(fā)起付款操作,資金操作完成后統(tǒng)一處理結(jié)果并更新單據(jù)信息,最后還有一些對(duì)上下游的異步通知,形式上包括消息和 RPC 回調(diào)。

我們將每個(gè)關(guān)鍵資金操作的狀態(tài)記錄落庫(kù),如下表所示。其中出款即錢從哪里來(lái),入款即錢到哪里去,沖正即回滾交易。在提現(xiàn)場(chǎng)景下就是從用戶支付賬戶出錢,到用戶的銀行卡去。其他場(chǎng)景比如充值(銀行卡->用戶支付賬戶),會(huì)有不同的資金流向。表中最后兩行加粗的場(chǎng)景還沒(méi)有達(dá)到終態(tài),是我們需要去補(bǔ)償?shù)摹?/p>

為了便于理解,我們?cè)谶@里省略了沖正的相關(guān)操作,一次余額提現(xiàn)流程的狀態(tài)機(jī)轉(zhuǎn)換如圖 3 所示。

圖 3.附帶狀態(tài)機(jī)轉(zhuǎn)換的余額提現(xiàn)流程

可重入與冪等性保證

發(fā)起一次支付會(huì)涉及到多個(gè)系統(tǒng)間調(diào)用,由于網(wǎng)絡(luò)原因?qū)е碌耐ㄐ懦瑫r(shí)是常見(jiàn)的問(wèn)題。同時(shí)上游系統(tǒng)也可能會(huì)重新發(fā)起請(qǐng)求,這需要我們的系統(tǒng)保證操作結(jié)果的冪等性。少數(shù)用戶也可能會(huì)有多個(gè)終端同時(shí)操作帶來(lái)的并發(fā)請(qǐng)求,需要我們保證接口的可重入性。除了服務(wù)自身,我們的下游依賴同樣也需要保證其接口具有同樣的能力。

先說(shuō)一說(shuō)什么是可重入與冪等性。

可重入:在并發(fā)請(qǐng)求下可以保證正確性。冪等性:重復(fù)多次相同的輸入,獲得相同的輸出。冪等性在技術(shù)上其實(shí)也包含了可重入的要求。

具體到業(yè)務(wù)中,冪等性是針對(duì)一筆已經(jīng)到達(dá)終態(tài)的支付而言的,對(duì)于初次未能拿到最終業(yè)務(wù)結(jié)果的請(qǐng)求,再次發(fā)起調(diào)用的結(jié)果可以是不同的(處理中->處理成功或失?。D敲次覀?nèi)绾伪WC業(yè)務(wù)流程的可重入與冪等性呢?我們分別拆解每一步來(lái)看:

生成支付單:首先支付單據(jù)可以將業(yè)務(wù)方傳遞的可保證唯一性的外部訂單號(hào)作為唯一索引,插入數(shù)據(jù)庫(kù)時(shí)若發(fā)生唯一索引沖突,則將查詢已有數(shù)據(jù)進(jìn)行冪等參數(shù)校驗(yàn),若與當(dāng)次請(qǐng)求的參數(shù)完全一致說(shuō)明是重復(fù)請(qǐng)求,可使用 DB 中的支付單繼續(xù)推進(jìn)后續(xù)流程;若不一致則返回錯(cuò)誤。資金處理流程:賬戶和渠道系統(tǒng)各自保證其接口冪等性。我們也維護(hù)了每個(gè)下游操作的狀態(tài),根據(jù)狀態(tài)機(jī)決定是否要繼續(xù)推進(jìn),盡量不向下游輸出重復(fù)流量。比如支付單已經(jīng)完成了所有資金處理,狀態(tài)機(jī)已經(jīng)是終態(tài),那么接口可以直接返回相應(yīng)結(jié)果。更新支付單信息,先將支付單加行級(jí)排他鎖,再進(jìn)行更新,保證多個(gè)并發(fā)請(qǐng)求只會(huì)有一個(gè)成功。異步通知,在支付單推進(jìn)到終態(tài)后進(jìn)行。

有了可重入與冪等性保證,我們就可以大量地復(fù)用正向流程來(lái)實(shí)現(xiàn)補(bǔ)單接口。

3.2 初始版

一般來(lái)說(shuō)最常見(jiàn)的補(bǔ)單形式是設(shè)置一個(gè)定時(shí)任務(wù),定時(shí)去掃表完成業(yè)務(wù)補(bǔ)償,實(shí)現(xiàn)比較簡(jiǎn)單,但是及時(shí)性不夠,對(duì)于收款轉(zhuǎn)賬類的交易而言用戶體驗(yàn)不佳。我們采用了通過(guò)消息隊(duì)列進(jìn)行即時(shí)補(bǔ)償?shù)姆绞?,如圖 4 所示。補(bǔ)償消費(fèi)者并沒(méi)有去做補(bǔ)償工作,而是解析消息然后通過(guò) RPC 調(diào)用支付核心暴露的補(bǔ)償接口。為什么不在消費(fèi)者中直接補(bǔ)償?這么做主要是考慮將邏輯收斂到一處便于維護(hù)。

圖 4. 余額提現(xiàn)發(fā)生異常時(shí)的補(bǔ)單流程

當(dāng)然,補(bǔ)單可能依然失敗,我們可以再次發(fā)送補(bǔ)償消息。但不能一直這樣循環(huán)下去,所以需要設(shè)置一個(gè)最大重試次數(shù),超出后不再發(fā)送。當(dāng)補(bǔ)償多次都不成功時(shí),一般是下游系統(tǒng)出了問(wèn)題,這時(shí)我們需要放緩補(bǔ)償?shù)念l次,隨著重試次數(shù)增加,會(huì)讓每次補(bǔ)償時(shí)間間隔逐漸增大,通過(guò) RocketMQ 的延時(shí)消息實(shí)現(xiàn)。

這里有三個(gè)很容易想到的問(wèn)題:

如果異常消息發(fā)送失敗,上游也沒(méi)有重試機(jī)制,這筆訂單就可能一直掛在這里不了了之了,如圖 5 所示。補(bǔ)償消費(fèi)者請(qǐng)求支付核心補(bǔ)單時(shí)不成功,可能是超時(shí)但實(shí)際補(bǔ)償成功了,或者是請(qǐng)求壓根沒(méi)有過(guò)去,如圖 6 所示。如果重試達(dá)到最大次數(shù)依然沒(méi)有成功,這筆單子該怎么處理。

圖 5. 補(bǔ)償消息發(fā)送失敗

圖 6. 補(bǔ)償消息消費(fèi)失敗

3.3 改進(jìn)版

針對(duì)問(wèn)題 1,如果重試依然發(fā)送失敗,我們通過(guò)引入一張異常消息表,將發(fā)送失敗的消息落庫(kù)來(lái)解決。表中記錄了訂單號(hào)、當(dāng)前的重試次數(shù)、異常分類、記錄狀態(tài)、消息體等字段。如果圖 6 中的第 4 步消息發(fā)送失敗,就將這筆訂單放入 DB 中的一張異常表中,會(huì)設(shè)置一個(gè)定時(shí)任務(wù)去處理。以目前 RocketMQ 的可用性來(lái)說(shuō),異常數(shù)據(jù)很少會(huì)出現(xiàn)。如圖 7 所示。

圖 7. 針對(duì)消息生產(chǎn)/消費(fèi)異常的改進(jìn)版 - 1

對(duì)于第 2 個(gè)問(wèn)題,如果補(bǔ)償消費(fèi)者調(diào)用支付核心失敗,補(bǔ)償消費(fèi)者 HandleMessage 會(huì)向上層拋出 error,利用 RocketMQ 的梯度重試機(jī)制,當(dāng)消費(fèi)重試次數(shù)達(dá)到一定上限后會(huì)進(jìn)入死信隊(duì)列。如圖 8 所示,這種情況一般是服務(wù)或網(wǎng)絡(luò)出了問(wèn)題,待恢復(fù)之后,可以從死信隊(duì)列拉取這些消息再統(tǒng)一處理。

圖 8. 針對(duì)消息生產(chǎn)/消費(fèi)異常的改進(jìn)版 - 2

當(dāng)然還有更極端的情況,請(qǐng)求 MQ 和 DB 都失敗了咋辦?以目前 MQ 和 DB 的可用性來(lái)說(shuō),同時(shí)失敗這種基本可以不用考慮,報(bào)警人工介入即可。

針對(duì)問(wèn)題 3,如果重試超過(guò)最大次數(shù),依然補(bǔ)償不成功,一般是下游依賴出了問(wèn)題。這種情況我們也將它放進(jìn)異常表中。

對(duì)于這兩類漏網(wǎng)之魚(yú),需要支持單條/批量支付單補(bǔ)償?shù)倪\(yùn)營(yíng)能力以供人工介入;最好有一個(gè)在業(yè)務(wù)低峰期運(yùn)行的兜底任務(wù),掃描業(yè)務(wù)單據(jù)表,將一段時(shí)間內(nèi)還未完成的訂單進(jìn)行補(bǔ)償。

另外,兜底任務(wù)可能造成消息的短暫堆積,影響線上的實(shí)時(shí)補(bǔ)償流程推進(jìn),對(duì)此可以使用獨(dú)立的隊(duì)列隔離開(kāi)來(lái)。

3.4 最終版

其實(shí)如果只是異步通知類的操作出現(xiàn)了異常,并沒(méi)有必要每次都重新走一遍完整業(yè)務(wù)流程,缺啥補(bǔ)啥即可。因此我們將異常劃分為多種類型,將一些異步操作和業(yè)務(wù)處理劃分開(kāi)來(lái),進(jìn)行精細(xì)化的處理:

通知下游的 MQ 失敗,就將這個(gè)消息體重發(fā)一次即可;通知交易的回調(diào) RPC 失敗,可將 RPC 請(qǐng)求序列化到消息體中,補(bǔ)償時(shí)通過(guò)反序列化消息體中的 RPC 請(qǐng)求,直接再發(fā)起一次 RPC 即可;對(duì)于更新 DB 失敗,將更新參數(shù)序列化到消息體中,補(bǔ)單時(shí)再次發(fā)起一次更新;如果在業(yè)務(wù)處理時(shí)遇到了異常情況,需要再走一遍業(yè)務(wù)補(bǔ)償;

圖 9 以這幾種異常為例,說(shuō)明了每種補(bǔ)償類型的消息參數(shù)。

圖 9. 分類補(bǔ)償

我們最終的補(bǔ)單體系見(jiàn)圖 10,它既通過(guò)即時(shí)消息保證了補(bǔ)償?shù)募皶r(shí)性,是主動(dòng)出擊之茅;也利用延時(shí)消息重試、落地失敗消息的異常表與兜底任務(wù)保證了補(bǔ)償?shù)挠行?,是萬(wàn)無(wú)一失之盾。不僅可用于支付單據(jù)的補(bǔ)償,通過(guò)保證流程的可重入性,也可作為一種通用解決方案,但不適用于無(wú)狀態(tài)、不可重入的業(yè)務(wù)形態(tài)。

圖 10. 異常補(bǔ)償體系

4.總結(jié)

本文首先介紹了什么是補(bǔ)單,接著基于三方支付系統(tǒng)的實(shí)現(xiàn)完整闡述了補(bǔ)單機(jī)制的演進(jìn)過(guò)程,最終演化為一種相對(duì)通用的異常處理模式,即基于消息隊(duì)列、有限狀態(tài)機(jī)與多重任務(wù)兜底的業(yè)務(wù)層最終一致性保障機(jī)制,供大家參考指正。

更多分享

UME - 豐富的Flutter調(diào)試工具

一例 Go 編譯器代碼優(yōu)化 bug 定位和修復(fù)解析

字節(jié)跳動(dòng)破局聯(lián)邦學(xué)習(xí):開(kāi)源Fedlearner框架,廣告投放增效209%

抖音品質(zhì)建設(shè) - iOS啟動(dòng)優(yōu)化《原理篇》

歡迎關(guān)注「 字節(jié)跳動(dòng)技術(shù)團(tuán)隊(duì) 」

簡(jiǎn)歷投遞聯(lián)系郵箱「 tech@bytedance.com 」

以上就是關(guān)于pos機(jī)退款需要先支付嗎,基于有限狀態(tài)機(jī)與消息隊(duì)列的三方支付系統(tǒng)補(bǔ)單實(shí)踐的知識(shí),后面我們會(huì)繼續(xù)為大家整理關(guān)于pos機(jī)退款需要先支付嗎的知識(shí),希望能夠幫助到大家!

轉(zhuǎn)發(fā)請(qǐng)帶上網(wǎng)址:http://m.afbey.com/news/49293.html

你可能會(huì)喜歡:

版權(quán)聲明:本文內(nèi)容由互聯(lián)網(wǎng)用戶自發(fā)貢獻(xiàn),該文觀點(diǎn)僅代表作者本人。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如發(fā)現(xiàn)本站有涉嫌抄襲侵權(quán)/違法違規(guī)的內(nèi)容, 請(qǐng)發(fā)送郵件至 babsan@163.com 舉報(bào),一經(jīng)查實(shí),本站將立刻刪除。