避免重復(fù)扣款:分布式支付系統(tǒng)的冪等性原理與實(shí)踐
在分布式支付系統(tǒng)中,冪等性是確保交易準(zhǔn)確性和用戶信任的核心原則之一。本文從支付架構(gòu)設(shè)計(jì)的角度,深入探討了冪等性原理及其在支付系統(tǒng)中的重要性,分析了業(yè)務(wù)冪等、通用冪等組件、全局冪等等多種實(shí)現(xiàn)方案及其適用場(chǎng)景,并討論了分布式場(chǎng)景下實(shí)現(xiàn)冪等性的挑戰(zhàn)與應(yīng)對(duì)策略,供大家參考。
今天聊一個(gè)專業(yè)的技術(shù)問(wèn)題:如何做到分布式場(chǎng)景下的冪等?本文主要講清楚什么是冪等性原理,在支付系統(tǒng)中的重要應(yīng)用,業(yè)務(wù)冪等、全部?jī)绲冗@些不同的冪等方案選型帶來(lái)的收益和復(fù)雜度權(quán)衡,冪等擊穿場(chǎng)景及可能的嚴(yán)重后果。
這也是支付公司面試的必考題目之一。
一、什么是冪等性原理
冪等性是一個(gè)數(shù)學(xué)和計(jì)算機(jī)科學(xué)術(shù)語(yǔ),用于描述無(wú)論操作執(zhí)行多少次,都產(chǎn)生相同結(jié)果的屬性。在軟件行業(yè),應(yīng)用極其廣泛,當(dāng)我們說(shuō)一個(gè)接口支持冪等時(shí),無(wú)論調(diào)用多少次,對(duì)系統(tǒng)造成的結(jié)果是一致的。
注意這里說(shuō)的“對(duì)系統(tǒng)造成的結(jié)果是一致的”是指系統(tǒng)內(nèi)部數(shù)據(jù)或狀態(tài)的變更,不是指返回值。不同的系統(tǒng)設(shè)計(jì),返回值可能是不一樣的。
舉個(gè)例子,你在淘寶免密支付10元,淘寶針對(duì)這筆訂單調(diào)用支付寶支付接口進(jìn)行支付,無(wú)論是調(diào)用1次,還是調(diào)用100次,最終只扣了你10元。但是第二次有可能返回“重復(fù)請(qǐng)求”,也有可能返回“支付成功”,這個(gè)取決于接口設(shè)計(jì)。也就是支付寶內(nèi)部只扣了你10元,但是接口可能返回給商戶是是不同的結(jié)果。
我個(gè)人傾向于方案一,如果等冪等,就返回:重復(fù)請(qǐng)求。減少誤解,雖然兩種方案中系統(tǒng)都只扣了一次錢。
二、為什么冪等性在支付系統(tǒng)中極其重要
支付系統(tǒng)必須以最高的可靠性和準(zhǔn)確性處理交易,這對(duì)于用戶信任至關(guān)重要。如果一個(gè)支付系統(tǒng)不能保證冪等性,可能會(huì)導(dǎo)致多次扣除同一筆費(fèi)用,引發(fā)用戶不滿和法律責(zé)任,嚴(yán)重時(shí)就會(huì)有輿情風(fēng)險(xiǎn),甚至?xí)坏蹁N牌照。
一般情況下,支付系統(tǒng)的冪等性能力要求比電商系統(tǒng)要求更高,如果用戶在電商下單多了,只要沒(méi)有支付,用戶還是可以忍受的,但一旦多扣了用戶的錢,后果就會(huì)比較嚴(yán)重。
這也是為什么冪等性會(huì)是支付系統(tǒng)招人的面試必考題目之一。
三、支付系統(tǒng)中應(yīng)用冪等性的場(chǎng)景
冪等是針對(duì)重復(fù)請(qǐng)求的,支付系統(tǒng)一般會(huì)面臨以下幾個(gè)重復(fù)請(qǐng)求的場(chǎng)景:
用戶多次點(diǎn)擊支付按鈕:在網(wǎng)絡(luò)較差或系統(tǒng)過(guò)載情況下,用戶由于不確定交易是否完成而重復(fù)點(diǎn)擊。
自動(dòng)重試機(jī)制:系統(tǒng)在超時(shí)或失敗時(shí)重試請(qǐng)求,可能導(dǎo)致同一支付多次嘗試。
網(wǎng)絡(luò)數(shù)據(jù)包重復(fù):數(shù)據(jù)包在網(wǎng)絡(luò)傳輸過(guò)程中,復(fù)制出了多份,導(dǎo)致支付平臺(tái)收到多次一模一樣的請(qǐng)求。
異?;謴?fù):在系統(tǒng)升級(jí)或崩潰后,未決事務(wù)需要根據(jù)已有記錄恢復(fù)和完成。內(nèi)部系統(tǒng)重發(fā)操作。
四、冪等解決方案
4.1. 業(yè)務(wù)冪等
所謂業(yè)務(wù)冪等,就是由各域自己把唯一性的交易ID作為數(shù)據(jù)庫(kù)唯一索引,這樣可以保證不會(huì)重復(fù)處理。
在數(shù)據(jù)庫(kù)前面可以加一層緩存來(lái)提高性能,但是緩存只用于查詢,查到數(shù)據(jù)認(rèn)為就返回冪等成功,但是但不到,需要嘗試插入數(shù)據(jù)庫(kù),插入成功后再刷新數(shù)據(jù)到緩存。
為什么要使用數(shù)據(jù)庫(kù)的唯一索引做為兜底,是因?yàn)榫彺媸强赡苁У摹?/p>
在面臨時(shí)經(jīng)常有同學(xué)只回答到“使用redis分布式鎖來(lái)實(shí)現(xiàn)冪等”,這是不對(duì)的。因?yàn)榫彺嬗锌赡苁?,分布式鎖只是用于防并發(fā)操作的一種手段,無(wú)法根本性解決冪等問(wèn)題,冪等一定是依賴數(shù)據(jù)庫(kù)的唯一索引解決。
大部分簡(jiǎn)單的支付系統(tǒng)只要有業(yè)務(wù)冪等基本也夠用了。
4.2. 通用冪等組件
每個(gè)域都要做冪等處理,那就單獨(dú)出一個(gè)獨(dú)立的冪等組件,各子業(yè)務(wù)系統(tǒng)通過(guò)引用這個(gè)公共JAR包解決。
適用場(chǎng)景:應(yīng)用部署不太多的時(shí)候。如果應(yīng)用非常多,獨(dú)立冪等DB的連接池就不夠用。
這個(gè)時(shí)候,可以把冪等組件的代碼共用,但是冪等數(shù)據(jù)庫(kù)表使用業(yè)務(wù)系統(tǒng)的DB資源。解決獨(dú)立冪等DB導(dǎo)致的連接數(shù)不夠用的場(chǎng)景。
4.3. 通用冪等服務(wù)
解決DB連接數(shù)不夠用的第二個(gè)解決方案:冪等組件服務(wù)化。這樣的壞處就是復(fù)雜度和耗時(shí)RT都會(huì)增加,而且冪等服務(wù)有可能成為瓶頸,所以一般很少這么用。
4.4. 全局冪等
在多機(jī)房部署情況下,需要解決機(jī)房之間的冪等服務(wù)。這就使用到了全局冪等概念。
所謂全局冪等,就是多個(gè)機(jī)房共用一份冪等數(shù)據(jù),這里面涉及的技術(shù)比較復(fù)雜。除了極少數(shù)全球部署的多活支付系統(tǒng)都用不上。
4.5. 通用冪等數(shù)據(jù)庫(kù)表設(shè)計(jì)
核心字段:
- uniqueKey:冪等主鍵,由各應(yīng)用自定義,需要保證全局唯一性,使用這個(gè)uniqueKey做hash后分庫(kù)分表。比如商戶的收單ID,上游的ID等。
- appName: 應(yīng)用名稱,比如收單,支付等。
- siteId:站點(diǎn)ID
- extInfoMap:擴(kuò)展字段,由各應(yīng)用自定義,比如保存我方單號(hào)。
4.6. 方案選型建議
簡(jiǎn)單的支付系統(tǒng),只需要使用業(yè)務(wù)冪等就夠。
中型的支付系統(tǒng),推薦使用通用冪等組件。這樣方便運(yùn)維。
全局冪等方案只有極少數(shù)公司會(huì)考慮。
五、分布式場(chǎng)景下實(shí)現(xiàn)冪等性的挑戰(zhàn)及應(yīng)對(duì)
分布式支付系統(tǒng)面臨的冪等性挑戰(zhàn)核心有兩點(diǎn):
- 如何保證分布于不同地理位置數(shù)據(jù)中心的系統(tǒng)數(shù)據(jù)的一致性。
- 冪等數(shù)據(jù)和業(yè)務(wù)數(shù)據(jù)跨庫(kù)事務(wù)一致性。比如冪等已經(jīng)入庫(kù)成功,但是業(yè)務(wù)數(shù)據(jù)庫(kù)入庫(kù)失敗。
為了解決這些挑戰(zhàn),可以采取以下解決方案:
- 使用全局唯一的交易ID,跟蹤每次支付請(qǐng)求,防止重復(fù)處理。
- 冪等住了之后,還需要繼續(xù)查詢業(yè)務(wù)數(shù)據(jù),如果查詢失敗,仍然執(zhí)行業(yè)務(wù)操作。
- 構(gòu)建強(qiáng)大的狀態(tài)機(jī)推進(jìn)能力,嚴(yán)格定義事務(wù)各個(gè)狀態(tài)的轉(zhuǎn)換。
- 冪等服務(wù)的高可靠性。
六、冪等被擊穿場(chǎng)景及可能的嚴(yán)重后果
盡管有了上述措施,冪等性仍然可能因?yàn)橐韵略蚴В?/p>
- 在分布式系統(tǒng)中,由于同步延遲,導(dǎo)致多個(gè)節(jié)點(diǎn)未能即時(shí)識(shí)別重復(fù)請(qǐng)求。
- 請(qǐng)求流量切換。原本應(yīng)該路由A機(jī)房的數(shù)據(jù)路由到了B機(jī)房,但是B機(jī)房的冪等數(shù)據(jù)缺失。
- 生成全局唯一ID的算法出現(xiàn)故障或人為變更,同一筆業(yè)務(wù)可能出現(xiàn)了2個(gè)業(yè)務(wù)ID。
在支付系統(tǒng)中,只要冪等被擊穿,基本上都會(huì)出現(xiàn)資損事件。有時(shí)候是用戶資損,有時(shí)候是平臺(tái)資損。曾經(jīng)碰到一個(gè)真實(shí)案例,上游域把某個(gè)冪等字段組成規(guī)則的取值變了,但是下游不知道,導(dǎo)致下游冪等失敗,對(duì)同一筆業(yè)務(wù)處理了2次,資損出現(xiàn)。
七、結(jié)束語(yǔ)
冪等性是分布式支付系統(tǒng)的基本要求,對(duì)于確保交易的正確性和避免重復(fù)扣費(fèi)至關(guān)重要。除了支付系統(tǒng)外,各種交易類的互聯(lián)網(wǎng)應(yīng)用比如電商等基本上都需要有冪等能力。
本文由人人都是產(chǎn)品經(jīng)理作者【隱墨星辰】,微信公眾號(hào):【隱墨星辰】,原創(chuàng)/授權(quán) 發(fā)布于人人都是產(chǎn)品經(jīng)理,未經(jīng)許可,禁止轉(zhuǎn)載。
題圖來(lái)自Unsplash,基于 CC0 協(xié)議。
good