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