支付流程設(shè)計常見問題及最佳實踐
在實際操作中,支付流程常常面臨諸多問題。本文將深入探討支付流程設(shè)計中的常見問題及其最佳實踐,供大家參考。
今天聊一下支付流程設(shè)計的一些常見總是及最佳實踐,包括:
組合支付要不要拆支付流水,前端輪詢查哪個域,查詢要不要穿透到外部渠道,為什么要做同步受理異步處理,支付補(bǔ)償怎么做,如何防重復(fù)支付,萬一重復(fù)支付了怎么做,支付成功后用戶關(guān)單了怎么做,返回碼怎么映射,支付要不要做系統(tǒng)自動重試,支付渠道如何做隔離。
一、組合支付要不要拆支付流水
當(dāng)然拆。不拆能不能做?也是可以做,但是壞處很多。有更優(yōu)解的情況下,我們要選擇更優(yōu)解。
每一種支付方式都有自己的特性,包括但不限于支付金額、支付時間、狀態(tài)等,如果放在一筆支付單,如何表達(dá)得清楚?
這里還有一個分層的概念,就是面向商戶的是收單域,生成的是交易單,交易單下面可以掛一個主支付單,這個支付單是支付域的,一個支付單下面掛多個支付流水,一個支付方式就生成一筆支付流水。
由支付域來負(fù)責(zé)多個支付方式的組合,以及主支付單的推進(jìn)。
二、前端輪詢查哪個域
有人查收單域,有人查支付域。
我的觀點是查收單域。因為收單是針對商戶的,商戶的訂單成功了,才算成功。有時候可能內(nèi)部出現(xiàn)故障,導(dǎo)致支付域成功但收單域沒有成功,還有可能訂單因為超時或用戶主動操作已經(jīng)關(guān)閉,這個時候支付域哪怕成功,也需要給用戶退回去。
如果是用戶充值,就以資金產(chǎn)品域為準(zhǔn)。
為避免對收單域的數(shù)據(jù)庫造成過大壓力,建議加一層緩存。
標(biāo)準(zhǔn)收銀臺和前置收銀臺又有一點不一樣。上面說的是前置收銀臺的情況。
三、查詢要不要穿透到外部渠道
很多人喜歡直接把查詢穿透到外部渠道,比如用戶提交支付后,在收銀臺頁面轉(zhuǎn)菊花,收銀臺頁面會有一個定時任務(wù)高頻查詢后端的支付結(jié)果,這個查詢請求鏈路:收銀臺頁面->收銀臺后端->收單域->支付域->渠道網(wǎng)關(guān)域->外部渠道。
如果一旦網(wǎng)絡(luò)抖動或外部渠道抽風(fēng),返回耗時增加,就會快速把內(nèi)部應(yīng)用的線程全部耗盡,極易引發(fā)雪崩。有興趣的可以翻翻公眾號前段時間發(fā)布的關(guān)于雪崩的超級故障。
正確的做法:
收銀臺只查自己的緩存,支付域有新數(shù)據(jù)后,更新到緩存,比如支付成功,或者需要跳到核身驗證頁面。
四、為什么要做同步受理異步處理
原理和上面的查詢不要穿透到外部渠道是一個道理,如果一旦網(wǎng)絡(luò)抖動或外部渠道抽風(fēng),返回耗時增加,就會快速把內(nèi)部應(yīng)用的線程全部耗盡,極易引發(fā)雪崩。
正確的做法:同步受理商戶的請求后,馬上返回給商戶,然后再異步處理,發(fā)送給渠道。
是不是每個域都做同步受理異步處理?也不是,那樣就太復(fù)雜了。
可以選擇在收單域做,也可以選擇在渠道網(wǎng)關(guān)域做。推薦在渠道網(wǎng)關(guān)域做,因為外部渠道的耗時最不可控,大不了多部署幾臺網(wǎng)關(guān),多開些線程。還有一個情況,比如只需要扣余額,那就直接毫秒級扣完返回給商戶,簡單實用。
如果一定要選擇所有域都做,那也是個人的自由。但強(qiáng)烈不建議全部同步調(diào)用出去。
五、支付狀態(tài)補(bǔ)償怎么做
支付發(fā)出后,有四種情況可以獲得支付的結(jié)果:
- 渠道接口實時返回渠道處理的結(jié)果。
- 渠道異步通知支付平臺。
- 支付平臺使用定時任務(wù)梯度時間查詢渠道支付結(jié)果。
- 拿到渠道對賬文件。
時效性而言,依次遞減,但也不是絕對的,有時候會出現(xiàn)渠道異步通知比接口實時返回還要快。這個時候一定要設(shè)計好狀態(tài)機(jī),否則很容易出現(xiàn)異步結(jié)果已經(jīng)推進(jìn)成功,實時接口又推進(jìn)到支付中。
定時查詢查詢一定要用梯度,一方面減少自己平臺和渠道壓力,同時又能獲得最好的時效性,比如間隔時間:1秒,2秒,5秒,10秒,20秒,40秒,100秒 … … 查到n次就不查了。再查下去也沒有意義,就等渠道文件對賬好了。如果渠道的對賬文件是支付成功,但是平臺支付已經(jīng)關(guān)閉訂單,那就走差錯給用戶退回去就好。
六、如何防重復(fù)支付
重復(fù)支付在很多公司都出現(xiàn)過,強(qiáng)大如支付寶,也時不時爆出大批量的重復(fù)支付。
首先是接口要有冪等設(shè)計。冪等的設(shè)計也有很多種方式,有人喜歡使用redis分布式鎖,我個人是反對的,起碼也要使用數(shù)據(jù)庫唯一索引。單機(jī)房使用唯一索引就夠,如果全球多活怎么辦?還得有一個全局冪等組件。具體怎么設(shè)計,可以在公眾號里找下:支付冪等設(shè)計與最佳實踐。
但是,冪等設(shè)計是基于商戶不換號的情況下,如果商戶換號重發(fā),就防不住,怎么辦?最好是基于用戶的維度做個判斷,比如同一個用戶,在短時間(比如1分鐘),已經(jīng)存在相同金額的支付單,就給用戶提示:“當(dāng)前已經(jīng)有一筆xx金額的訂單,是否仍然支付?”。雖然不能完全避免,但是可以減少。
七、萬一重復(fù)支付了怎么做
前面有提出防重復(fù)支付,但是萬一真出現(xiàn)重復(fù)支付了怎么辦?
沒有什么好辦法,原路退回就是。
這也是我們?yōu)槭裁丛谇懊姘呀灰讍魏椭Ц秵螀^(qū)分出來的原因。各是各的單,出現(xiàn)問題好處理。
還有一個問題,如何發(fā)現(xiàn)內(nèi)部有大批量的重復(fù)支付?總不能全部等客訴吧?后面有時間再聊聊支付平臺內(nèi)部多域之間實時兩兩對賬。
八、支付成功后用戶關(guān)單了怎么做
不僅是重復(fù)支付后需要原路退回,如果渠道扣款成功,但是我們的訂單已經(jīng)關(guān)閉(超期關(guān)閉,用戶主動關(guān)閉等),都需要做原路退回。
這里還可以引申出另外一個問題,為什么記賬的時候,有一個“商戶待結(jié)算戶:,還有一個“支付網(wǎng)關(guān)過渡戶”。如果沒有支付網(wǎng)關(guān)過渡戶,支付成功,錢直接到了商戶待結(jié)算戶,但是如果收單域的訂單已經(jīng)關(guān)閉,這筆錢就不應(yīng)該進(jìn)入到商戶待結(jié)算戶里去,而是應(yīng)該直接從支付網(wǎng)關(guān)過渡戶給用戶退回去。
九、返回碼怎么映射
對于支付來說,不要輕易推進(jìn)到成功,只有渠道非常明確地說,某個返回碼代表成功,才能推進(jìn)成功。否則很容易出現(xiàn)資損。
當(dāng)然也不要輕易推進(jìn)失敗,也只有明確失敗才能推進(jìn)失敗,否則用戶支付成功被推進(jìn)失敗,容易引起客訴。
尤其要注意的是,有很多渠道有兩級返回碼,要區(qū)分如何組合使用。還有,查詢接口一定要區(qū)分通信成功和業(yè)務(wù)成功,只能通過業(yè)務(wù)成功來推進(jìn)狀態(tài)。
更詳細(xì)的說明,可以翻翻公眾號的文章;返回碼映射設(shè)計與最佳實踐。
十、支付要不要做系統(tǒng)自動重發(fā)
網(wǎng)絡(luò)經(jīng)常超時,如果用戶發(fā)起支付,超時了,再次重試,就會成功,那到底要不要系統(tǒng)自動重試呢?建議根據(jù)自己的業(yè)務(wù)場景和團(tuán)隊的技術(shù)實力選擇。
業(yè)務(wù)場景,比如代扣,一定要系統(tǒng)自動重試,包括余額不足,超時等場景都需要重試。余額不足再換個支付方式或換張卡再試,超時多次查詢都返回“訂單不存在”,那也需要系統(tǒng)自動重試。
如果是普通的支付,那看團(tuán)隊是否能做到避免重復(fù)扣款,如果能,那就系統(tǒng)自動重試,提高成功率。給一個思路:特定的返回碼 + 指定時間內(nèi)查詢都是返回“訂單不存在”。
十一、支付渠道如何做隔離
有人喜歡為每一個渠道都編寫?yīng)毩⒌拇a,美其名曰:“隔離性好”,一個渠道有問題不影響另外一個。
我卻覺得技術(shù)和架構(gòu)能力需要提高。渠道接入四個層次:
- 為每個渠道寫?yīng)毩⒌拇a。
- 抽象出模板方式,每個渠道只需要寫特定的代碼,比如報文組裝、簽名驗簽。流程由模板方法驅(qū)動。
- 配置文件接入渠道。把渠道的處理分解成多個子能力,通過配置文件驅(qū)動。
- 直接在后臺頁面配置映射就能接入。
只要領(lǐng)域抽象能力強(qiáng),技術(shù)過硬,哪怕做到第四層,仍然可以做到很好的隔離。比如通過外部渠道分配的商戶號,隔離出不同的配置,不同的渠道配置不同的參數(shù),自動化測試回歸,保存歷史報文用于自動化MOCK測試等。質(zhì)量仍然是上乘的,隔離性也完全沒問題。
本文由人人都是產(chǎn)品經(jīng)理作者【隱墨星辰】,微信公眾號:【隱墨星辰】,原創(chuàng)/授權(quán) 發(fā)布于人人都是產(chǎn)品經(jīng)理,未經(jīng)許可,禁止轉(zhuǎn)載。
題圖來自Unsplash,基于 CC0 協(xié)議。
- 目前還沒評論,等你發(fā)揮!