訂單服務(wù)的設(shè)計(jì)思考

項(xiàng)目背景

最近由于項(xiàng)目業(yè)務(wù)原因,需要為系統(tǒng)設(shè)計(jì)虛擬幣的充值及消費(fèi)功能。公司內(nèi)已經(jīng)有成熟的支付網(wǎng)關(guān)服務(wù),所以重點(diǎn)變成了如何設(shè)計(jì)項(xiàng)目?jī)?nèi)虛擬幣的充值流程,讓整個(gè)充值流程都實(shí)現(xiàn)冪等,確保用戶的虛擬幣余額不會(huì)重復(fù)增加或扣減。

商品購(gòu)買及支付流程

微信支付時(shí)序圖

(1)用戶購(gòu)買商品,商戶后臺(tái)請(qǐng)求生成支付訂單并返回相關(guān)信息到客戶端。
(2)客戶端根據(jù)返回的信息喚起支付SDK,用戶確認(rèn)支付。
(3)用戶完成支付后,支付系統(tǒng)會(huì)異步通知商戶后臺(tái)支付結(jié)果。
(4)商戶后臺(tái)接收支付回調(diào),在回調(diào)接口內(nèi)完成自己的業(yè)務(wù)邏輯。
(5)客戶端在支付完成后延時(shí)一定時(shí)間從商戶后臺(tái)查詢支付結(jié)果,此時(shí)若尚未接收到支付回調(diào),可主動(dòng)同步支付結(jié)果(保底策略)。

支付寶支付流程和微信支付類似,此處省略。正常情況下支付回調(diào)都會(huì)在毫秒級(jí)別進(jìn)行通知回調(diào)。

虛擬幣充值流程

虛擬幣充值流程會(huì)嵌套支付回調(diào)流程中。若虛擬幣沒有完成完整的業(yè)務(wù)流程,支付系統(tǒng)會(huì)進(jìn)行重試。因此業(yè)務(wù)流程需要支持冪等。


虛擬幣充值流程

在實(shí)踐過程遇到以下問題并最終得到解決:
(1)如何支持訂單按用戶維度分表?
支付回調(diào)信息只包括訂單ID信息,在這種情況下一般只能根據(jù)訂單ID進(jìn)行分表。考慮到訂單會(huì)越來越多,我們一開始就把訂單按用戶維度進(jìn)行分表。一般情況下按用戶維度的查詢是很多的,而單純按訂單維度的查詢會(huì)比較少。所以在預(yù)下單的時(shí)候把用戶ID信息寫入attach附加信息,支付回調(diào)時(shí)會(huì)攜帶上原先的附加信息,這樣就可以知道用戶及訂單ID信息,完成后續(xù)操作。

在后來的優(yōu)化中,訂單ID生成時(shí)預(yù)留低位段存儲(chǔ)用戶訂單表ID信息,這樣完全不依賴附加信息進(jìn)行傳遞,在用戶進(jìn)行自動(dòng)扣費(fèi)授權(quán)時(shí)的回調(diào)通知也可以適用。

(2)虛擬幣如何做事務(wù)操作?
若只有用戶虛擬幣的數(shù)量信息,很容易會(huì)出現(xiàn)錯(cuò)誤的重復(fù)操作。因此需要流水表配合進(jìn)行事務(wù)操作,當(dāng)流水表已經(jīng)有相同的記錄時(shí)說明當(dāng)前操作是重復(fù)的,需要回滾虛擬幣數(shù)值。通過數(shù)據(jù)庫的單機(jī)事務(wù)即可實(shí)現(xiàn)虛擬幣的正確變更,支持重入。
(3)如何做虛擬幣的版本控制?
我們虛擬幣每次變更都會(huì)對(duì)應(yīng)一個(gè)版本號(hào),在對(duì)虛擬幣的并發(fā)操作時(shí)一般都是通過判斷version是否符合預(yù)期時(shí)才進(jìn)行數(shù)據(jù)變更。這個(gè)和樂觀鎖的控制類似,可是在這種情況下容易出現(xiàn)死鎖,尤其是數(shù)據(jù)庫性能差更容易觸發(fā)。因此不再嚴(yán)格判斷version版本號(hào),只需要變更后的虛擬幣數(shù)量不小于0即可,所有符合這個(gè)條件的變更都視為有效變更。這個(gè)情景適合不用版本號(hào),只更新是做數(shù)據(jù)安全校驗(yàn),適合庫存模型,性能更高。

update table_xxx set avai_amount=avai_amount+:deltaAmount where user_id=:userId and avai_amount+:deltaAmount >= 0

大多數(shù)情況下只有虛擬幣消費(fèi)才會(huì)出現(xiàn)并發(fā)修改,因此我們只需要嚴(yán)格控制虛擬幣不出現(xiàn)余額不足以扣除的情況。

蘋果內(nèi)購(gòu)虛擬幣充值流程

用戶在應(yīng)用內(nèi)購(gòu)買商品時(shí),客戶端可以獲取到用戶ID、交易憑證receipt和交易ID等信息。整體購(gòu)買流程和Android端差異比較大,因?yàn)閷?duì)receipt驗(yàn)證流程參考Android下單流程做了拆解,更容易做到重入。
(1)客戶端獲取到充值列表;
(2)客戶端支付成功后提交交易憑證receipt給服務(wù)端驗(yàn)證,服務(wù)端創(chuàng)建對(duì)應(yīng)的憑證和訂單記錄,更新狀態(tài),完成充值;


蘋果內(nèi)購(gòu)充值流程

蘋果內(nèi)購(gòu)有以下事項(xiàng)需要注意:
(1)如何避免receipt被重復(fù)使用?
iOS客戶端支付成功后能獲取到transactionId和receipt信息,兩者唯一對(duì)應(yīng)。因此服務(wù)端在驗(yàn)證receipt有效后,可創(chuàng)建對(duì)應(yīng)的transaction記錄,根據(jù)transactionId進(jìn)行分表,transactionId作為唯一鍵。這樣可避免receipt被重復(fù)使用。
(2)transaction和訂單記錄的映射關(guān)系
訂單記錄包含渠道transactionId信息,這樣在創(chuàng)建transaction記錄后也可以唯一綁定到訂單信息,避免重復(fù)創(chuàng)建訂單。

設(shè)計(jì)總結(jié)

在設(shè)計(jì)訂單系統(tǒng)時(shí)冪等性是首要考慮的問題,需要嚴(yán)格保證金額的準(zhǔn)確性,不能給用戶多扣款或多打款。一般情況下我們通過數(shù)據(jù)庫單機(jī)事務(wù)和冪等重試等方式提高訂單系統(tǒng)的健壯性。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容