聽(tīng)說(shuō)你會(huì)架構(gòu)設(shè)計(jì)?來(lái),弄一個(gè)在線(xiàn)支付系統(tǒng)
引言
你有沒(méi)有過(guò)這樣的經(jīng)歷?早晚高峰刷碼乘車(chē),點(diǎn)擊 “確認(rèn)支付” 后屏幕轉(zhuǎn)圈半天沒(méi)反應(yīng),手心直冒冷汗怕錯(cuò)過(guò)地鐵/公交;或者春節(jié)發(fā)紅包,剛點(diǎn)出去就提示 “支付失敗”,群里親友催著 “補(bǔ)一個(gè)” 的消息不斷彈出 —— 那一刻,是不是特別想知道:明明平時(shí)付款秒到,為啥關(guān)鍵時(shí)刻支付系統(tǒng)會(huì) “掉鏈子”?
如今我們出門(mén)不帶現(xiàn)金,買(mǎi)奶茶、打車(chē)、繳水電費(fèi)全靠手機(jī)在線(xiàn)支付,微信支付、支付寶每天要處理數(shù)十億筆交易,峰值時(shí)每秒甚至能扛住上百萬(wàn)次請(qǐng)求。
這背后的在線(xiàn)支付系統(tǒng),可不是簡(jiǎn)單的 “扣錢(qián) + 打款”,而是一套能抗住高并發(fā)、保障資金安全、實(shí)現(xiàn)跨平臺(tái)互通的復(fù)雜技術(shù)體系。
今天就帶大家扒一扒在線(xiàn)支付系統(tǒng)的 “家底”:從整體架構(gòu)到核心功能,到關(guān)鍵技術(shù)到踩過(guò)的坑。
看完這篇,你不僅能懂支付系統(tǒng)的運(yùn)作邏輯,下次再遇到支付問(wèn)題,還能跟朋友嘮嘮 “這大概率是某個(gè)環(huán)節(jié)的容災(zāi)沒(méi)做好”~
1. 整體架構(gòu)
在線(xiàn)支付系統(tǒng)就像一個(gè) “數(shù)字銀行柜臺(tái)”,既要對(duì)接用戶(hù)(客戶(hù)端)、商家(商戶(hù)系統(tǒng)),還要聯(lián)動(dòng)銀行、第三方支付機(jī)構(gòu)(如銀聯(lián)),同時(shí)得 防黑客、堵漏洞,確保每一筆錢(qián)都 “來(lái)去分明”。
它的核心是 “分層解耦 + 分布式架構(gòu)”,哪怕某一個(gè)模塊出問(wèn)題,也不會(huì)影響整體支付流程。
架構(gòu)圖:
圖片
在線(xiàn)支付系統(tǒng)的架構(gòu)可分為 “業(yè)務(wù)層” 和 “基礎(chǔ)層”,各組件分工明確又相互協(xié)作,具體如下:
層級(jí) | 核心組件 | 核心作用 |
業(yè)務(wù)層 | 客戶(hù)端 | 用戶(hù)操作入口,負(fù)責(zé)渲染支付界面、調(diào)用支付 SDK、接收支付結(jié)果通知 |
API 網(wǎng)關(guān) | 系統(tǒng) “交通樞紐”,處理請(qǐng)求路由、鑒權(quán)、限流、日志記錄 | |
支付核心服務(wù) | 系統(tǒng) “大腦”,包含 | |
賬戶(hù)服務(wù) | 管理資金賬戶(hù),負(fù)責(zé)余額查詢(xún)、充值、提現(xiàn)、凍結(jié),保障資金安全 | |
對(duì)賬服務(wù) | 系統(tǒng) “財(cái)務(wù)審計(jì)員”,每日與支付通道對(duì)賬,解決 “多扣錢(qián)”“漏打款” 問(wèn)題 | |
基礎(chǔ)層 | 分布式數(shù)據(jù)庫(kù) | 存儲(chǔ)訂單、賬戶(hù)等核心數(shù)據(jù),用分庫(kù)分表 + TiDB 應(yīng)對(duì)高并發(fā)讀寫(xiě) |
消息隊(duì)列(Kafka/RocketMQ) | 解耦服務(wù)依賴(lài),異步處理非核心流程(如積分發(fā)放、物流通知),避免流程卡頓 | |
分布式緩存(Redis 集群) | 緩存熱門(mén)配置、用戶(hù)余額、防重復(fù)令牌,減少數(shù)據(jù)庫(kù)壓力 | |
分布式鎖(Redis/ZooKeeper) | 解決并發(fā)沖突(如避免余額超扣),確保數(shù)據(jù)一致性 |
2. 支付發(fā)起:從 “點(diǎn)擊付款” 到 “等待支付”
你在奶茶店掃碼付款時(shí),看似簡(jiǎn)單的 “掃碼→輸密碼→支付成功”,背后其實(shí)經(jīng)歷了 6 個(gè)關(guān)鍵步驟。
這一步的核心是 “確保訂單不重復(fù)、金額不篡改、通道能兼容”。
業(yè)務(wù)流程圖如下:
圖片
具體流程拆解:
- 用戶(hù)觸發(fā)支付:你在商家 H5 頁(yè)面點(diǎn)擊 “微信支付”,客戶(hù)端攜帶 “商品 ID、金額(15 元)、商戶(hù) ID” 請(qǐng)求 API 網(wǎng)關(guān);
- 網(wǎng)關(guān)鑒權(quán)與路由:網(wǎng)關(guān)驗(yàn)證商戶(hù) API 密鑰是否有效(防止偽造請(qǐng)求),判斷請(qǐng)求頻率是否超限(比如該商戶(hù)每秒最多 10 筆),然后轉(zhuǎn)發(fā)到支付核心的 “訂單服務(wù)”;
- 生成支付訂單:訂單服務(wù)生成唯一訂單號(hào)(比如 P20250902123456789),校驗(yàn)金額是否合法(比如不能為 0 或負(fù)數(shù)),關(guān)聯(lián)商戶(hù)的支付通道配置(該商戶(hù)已開(kāi)通微信支付,配置了微信商戶(hù)號(hào)),將訂單數(shù)據(jù)寫(xiě)入 MySQL 分表;
- 請(qǐng)求支付通道:訂單服務(wù)調(diào)用 “通道服務(wù)”,通道服務(wù)根據(jù) “微信支付” 類(lèi)型,封裝微信支付需要的參數(shù)(如 appid、mch_id、nonce_str、簽名),調(diào)用微信支付的 “統(tǒng)一下單接口”;
- 獲取支付憑證:微信支付接口返回 “prepay_id”(預(yù)支付 ID),通道服務(wù)將其封裝成客戶(hù)端能識(shí)別的格式(比如微信 APP 支付需要的 sign、timestamp),通過(guò)網(wǎng)關(guān)返回給客戶(hù)端;
- 客戶(hù)端喚起支付:客戶(hù)端拿到憑證后,調(diào)用微信支付 SDK,喚起微信 APP 的支付界面,你輸入密碼或驗(yàn)證指紋后,微信開(kāi)始處理支付。
這里有兩個(gè)關(guān)鍵技術(shù)點(diǎn):
- 防重復(fù)提交:訂單服務(wù)生成訂單時(shí),會(huì)向 Redis 寫(xiě)入 “用戶(hù) ID + 商品 ID” 的令牌,有效期 5 分鐘,若同一用戶(hù) 5 分鐘內(nèi)重復(fù)發(fā)起同一商品的支付,直接返回已存在的訂單,避免生成多筆訂單;
- 簽名驗(yàn)證:通道服務(wù)調(diào)用支付通道時(shí),會(huì)用商戶(hù)的 API 密鑰對(duì)參數(shù)簽名,支付通道(如微信)收到請(qǐng)求后會(huì)重新計(jì)算簽名,若不一致則拒絕,防止參數(shù)被黑客篡改(比如把 15 元改成 1.5 元)。
3. 支付結(jié)果回調(diào):從 “支付成功” 到 “訂單完成”
你輸完密碼后,手機(jī)彈出 “支付成功” 提示,這時(shí)商家的收銀系統(tǒng)也會(huì)同步收到通知 —— 這一步靠的是 “支付通道異步回調(diào)”,核心是 “確保結(jié)果不丟失、狀態(tài)不混亂”。
業(yè)務(wù)時(shí)序圖如下::
圖片
具體流程拆解:
- 支付通道觸發(fā)回調(diào):微信支付完成扣款后,會(huì)向我們系統(tǒng)配置的 “回調(diào)地址”(比如https://pay.xxx.com/callback/wechat)發(fā)起 POST 請(qǐng)求,攜帶支付結(jié)果(訂單號(hào)、支付金額、交易狀態(tài) SUCCESS);
- 回調(diào)接口驗(yàn)簽:通道服務(wù)的回調(diào)接口先驗(yàn)證微信的簽名(防止偽造回調(diào),比如黑客偽造 “支付成功” 消息騙商家發(fā)貨),校驗(yàn)通過(guò)后解析回調(diào)參數(shù);
- 更新訂單狀態(tài):通道服務(wù)調(diào)用 “結(jié)果服務(wù)”,結(jié)果服務(wù)用分布式鎖鎖住該訂單號(hào)(防止同一訂單的兩次回調(diào)同時(shí)處理),查詢(xún)訂單當(dāng)前狀態(tài)(此時(shí)為 “待支付”),將其更新為 “支付成功”,同時(shí)記錄交易流水號(hào)(微信返回的 transaction_id);
- 異步通知關(guān)聯(lián)系統(tǒng):結(jié)果服務(wù)向 Kafka 發(fā)送 “支付成功” 消息,消息包含訂單號(hào)、用戶(hù) ID、金額,積分系統(tǒng)消費(fèi)消息給用戶(hù)加 15 積分,物流系統(tǒng)消費(fèi)消息觸發(fā) “打包發(fā)貨”(若為電商訂單);
- 通知客戶(hù)端結(jié)果:結(jié)果服務(wù)通過(guò) WebSocket 或推送(如極光推送)向用戶(hù)客戶(hù)端發(fā)送 “支付成功” 通知,同時(shí)調(diào)用商戶(hù)的 “回調(diào)接口”,告知商戶(hù)該訂單已支付;
- 日志與監(jiān)控:整個(gè)過(guò)程記錄詳細(xì)日志(包括回調(diào)參數(shù)、處理結(jié)果),同時(shí)上報(bào)監(jiān)控指標(biāo)(如 “支付成功數(shù)”“回調(diào)處理耗時(shí)”),若回調(diào)失敗(比如商戶(hù)接口超時(shí)),會(huì)觸發(fā)重試機(jī)制(每隔 10 分鐘重試一次,共重試 3 次)。
避坑重點(diǎn):回調(diào)重復(fù)處理
微信支付可能因網(wǎng)絡(luò)波動(dòng)發(fā)起兩次回調(diào),此時(shí)分布式鎖會(huì)生效:第一個(gè)回調(diào)拿到鎖后更新?tīng)顟B(tài),第二個(gè)回調(diào)拿鎖失敗,查詢(xún)訂單已成功則直接返回,避免重復(fù)扣減商戶(hù)余額。
4. 交易對(duì)賬:每天凌晨的 “財(cái)務(wù)審計(jì)”
你可能沒(méi)注意到,每天凌晨 2-4 點(diǎn),支付系統(tǒng)會(huì)自動(dòng)和微信、支付寶、銀行對(duì)賬 —— 這一步是 “資金安全的最后防線(xiàn)”,確保我們系統(tǒng)的交易數(shù)據(jù)和通道方一致,沒(méi)有 “多扣用戶(hù)錢(qián)” 或 “少收商家錢(qián)”。
對(duì)賬交互圖如下:
圖片
具體步驟:
- 獲取通道對(duì)賬文件:凌晨 2 點(diǎn),對(duì)賬服務(wù)自動(dòng)從微信支付、支付寶的后臺(tái)下載 “對(duì)賬文件”(如 CSV 格式,包含當(dāng)天每筆交易的訂單號(hào)、金額、手續(xù)費(fèi)、交易時(shí)間);
- 生成系統(tǒng)對(duì)賬文件:對(duì)賬服務(wù)從 MySQL 分表、TiDB 中讀取當(dāng)天的所有支付訂單,拉取 訂單號(hào)、交易流水號(hào)、金額數(shù)、交易狀態(tài) 等關(guān)鍵字段;
- 字段匹配對(duì)賬:對(duì)賬服務(wù)按 “訂單號(hào)” 或 “交易流水號(hào)” 關(guān)聯(lián)兩個(gè)文件,對(duì)比關(guān)鍵字段:
圖片
- 金額一致、交易狀態(tài)一致(系統(tǒng)顯示成功,通道也顯示成功):標(biāo)記為 “對(duì)賬成功”;
- 系統(tǒng)有訂單,通道沒(méi)有:標(biāo)記為 “單邊賬(系統(tǒng)多)”,可能是通道回調(diào)沒(méi)收到,需要人工核實(shí);
- 通道有交易,系統(tǒng)沒(méi)有:標(biāo)記為 “單邊賬(通道多)”,可能是系統(tǒng)回調(diào)處理失敗,需要補(bǔ)錄訂單;
- 金額不一致:標(biāo)記為 “金額差異”,比如系統(tǒng)顯示 15 元,通道顯示 14.9 元,可能是手續(xù)費(fèi)計(jì)算錯(cuò)誤,需要查日志;
- 異常處理與歸檔:對(duì)賬服務(wù)將異常訂單推送到 “對(duì)賬異常平臺(tái)”,通知運(yùn)維和財(cái)務(wù)人員處理;處理完成后,將對(duì)賬結(jié)果歸檔到 HDFS(海量存儲(chǔ)),保留至少 3 年(符合金融監(jiān)管要求);
- 生成對(duì)賬報(bào)告:對(duì)賬服務(wù)生成當(dāng)天的對(duì)賬報(bào)告(總交易筆數(shù)、總金額、異常筆數(shù)、異常率),發(fā)送給運(yùn)營(yíng)和財(cái)務(wù)團(tuán)隊(duì)。
技術(shù)難點(diǎn):海量數(shù)據(jù)對(duì)賬效率
若某天有 1 億筆交易,對(duì)賬文件達(dá)幾十 GB,直接加載到內(nèi)存會(huì) OOM(內(nèi)存溢出)。
解決方案是 “分塊對(duì)賬 + Spark 分布式計(jì)算”:按訂單號(hào)哈希將文件分成 100 個(gè)塊,用 Spark 集群并行處理,對(duì)賬時(shí)間從 2 小時(shí)縮短至 30 分鐘。
6. 一些難點(diǎn)和要點(diǎn):支付系統(tǒng)的 “避坑指南”
做支付系統(tǒng)就像走鋼絲,既要扛住高并發(fā),又要保證資金安全,這些年小?做商業(yè)化的過(guò)程中踩過(guò)不少坑,也總結(jié)了一些解決方案,分享給大家~
1)高并發(fā)下的 “余額超扣” 問(wèn)題
場(chǎng)景:某電商大促時(shí),同一用戶(hù)同時(shí)發(fā)起兩筆支付(比如搶兩件商品),用戶(hù)余額只有 99 元,兩筆訂單各 50 元,理論上有一筆會(huì)被攔?。ㄒ?yàn)?100>99,用戶(hù)的余額不足以支付兩筆訂單),但并發(fā)下可能扣成 “-1 元”(超扣)。
原因:傳統(tǒng)的 “查詢(xún)余額→判斷是否足夠→扣減余額” 是串行操作,并發(fā)時(shí)會(huì)出現(xiàn) “臟讀”—— 第一個(gè)請(qǐng)求查詢(xún)余額 99 元,還沒(méi)扣減,第二個(gè)請(qǐng)求也查到 99 元,兩個(gè)請(qǐng)求都判斷 “足夠”,并發(fā)下兩筆訂單都判斷 99≥50,最終扣成 99-50-50=-1 元”。
解決方案:
- 用 “數(shù)據(jù)庫(kù)行鎖”:扣減余額時(shí)執(zhí)行UPDATE account SET balance = balance - 50 WHERE user_id = 123 AND balance >= 50,利用 MySQL 的行鎖確保同一用戶(hù)的扣減操作串行執(zhí)行,且只有余額足夠時(shí)才扣減;
- 加 “分布式鎖”:扣減前用 Redis 的 SETNX 命令獲取 “user_123_balance_lock” 鎖,獲取成功才執(zhí)行扣減,執(zhí)行完釋放鎖,防止并發(fā)操作。
通過(guò)這兩個(gè)方案,我們把 “余額超扣” 的概率降到了 0.001% 以下,剩下的通過(guò)對(duì)賬補(bǔ)正。
2)支付通道 “降級(jí)與容災(zāi)”:避免某通道掛了影響支付
場(chǎng)景:微信支付某天凌晨升級(jí),接口暫時(shí)不可用,若所有用戶(hù)都只能用微信支付,會(huì)導(dǎo)致支付失敗,影響商家生意。
原因:支付系統(tǒng)過(guò)度依賴(lài)單一通道,沒(méi)有備用方案,通道故障直接導(dǎo)致服務(wù)不可用。
解決方案:
- 通道降級(jí)策略:在通道服務(wù)中配置 “降級(jí)開(kāi)關(guān)”,當(dāng)微信支付接口失敗率超過(guò) 5%(通過(guò)監(jiān)控或者自動(dòng)化配置發(fā)現(xiàn)),自動(dòng)將該商戶(hù)的微信支付通道降級(jí)為 “支付寶支付”,客戶(hù)端只顯示支付寶選項(xiàng);
- 多通道容災(zāi):核心商戶(hù)開(kāi)通至少 2 個(gè)支付通道(如微信 + 支付寶),通道服務(wù)根據(jù) “通道健康度”(成功率、響應(yīng)時(shí)間)動(dòng)態(tài)選擇最優(yōu)通道,比如微信響應(yīng)慢時(shí),自動(dòng)路由到支付寶;
- 本地緩存通道配置:將商戶(hù)的通道配置緩存到 Redis,即使通道服務(wù)掛了,訂單服務(wù)也能從緩存中獲取通道信息,發(fā)起支付請(qǐng)求。
當(dāng)然這只是考慮可能的意外情況,實(shí)際上微信支付和支付寶通道支付的可用性至少為 6 個(gè) 9(如 99.9999%),一年只有 31s 的不可服務(wù)時(shí)間。
但我們之前在做海外 Google/App Store 支付時(shí),就遇到過(guò)網(wǎng)絡(luò)訪(fǎng)問(wèn)失敗的類(lèi)似情況,某支付通道臨時(shí)故障,我們的降級(jí)策略在 10 秒內(nèi)生效,將 98% 的請(qǐng)求路由到備用通道,支付成功率僅下降 0.2%,幾乎沒(méi)影響用戶(hù)體驗(yàn)。
3)防刷單與防欺詐:守住資金安全大門(mén)
場(chǎng)景:黑客偽造商戶(hù)生成虛假訂單,用盜刷銀行卡支付后申請(qǐng)退款,套取資金原因:缺乏有效的風(fēng)控機(jī)制,異常交易識(shí)別不及時(shí)解決方案:
- 商戶(hù)風(fēng)控:入駐時(shí)嚴(yán)格審核營(yíng)業(yè)執(zhí)照、法人身份證、對(duì)公賬戶(hù),開(kāi)通通道前完成實(shí)名認(rèn)證;
- 交易風(fēng)控:基于用戶(hù)行為(如 IP 地址、設(shè)備號(hào)、支付頻率)建立風(fēng)控模型,異常交易(如同一設(shè)備 10 分鐘內(nèi)支付 5 筆)觸發(fā)人工審核;
- 資金風(fēng)控:退款時(shí)校驗(yàn) “原支付賬戶(hù)” 與 “退款賬戶(hù)” 一致性,防止資金轉(zhuǎn)入陌生賬戶(hù);大額退款(如超 1 萬(wàn)元)需人工二次審核。
其中原賬戶(hù)退款是金融產(chǎn)品比較常用的資金風(fēng)控方案,如:同花順、支付寶基金等都是如此,通過(guò)多層風(fēng)控,我們可以將欺詐交易率控制在 0.0001% 以下。
總結(jié):在線(xiàn)支付系統(tǒng)的 “技術(shù)核心”
在線(xiàn)支付系統(tǒng)不是簡(jiǎn)單的 “扣錢(qián) + 打款”,而是一套融合 “高并發(fā)處理、數(shù)據(jù)一致性保障、資金安全防護(hù)” 的復(fù)雜體系??偨Y(jié)下來(lái),它的核心要點(diǎn)可歸納為三點(diǎn):
- 架構(gòu)設(shè)計(jì):分層解耦 + 分布式通過(guò) API 網(wǎng)關(guān)、支付核心、賬戶(hù)服務(wù) 等組件分層設(shè)計(jì),配合 消息隊(duì)列、分布式緩存 等基礎(chǔ)組件,實(shí)現(xiàn) “高可用、可擴(kuò)展” —— 即使某模塊故障,整體流程也能正常運(yùn)轉(zhuǎn),支撐每秒百萬(wàn)級(jí)請(qǐng)求。
- 數(shù)據(jù)一致性:鎖 + 對(duì)賬雙保障用 分布式鎖、數(shù)據(jù)庫(kù)行鎖 解決并發(fā)沖突(如余額超扣、重復(fù)退款);用 每日對(duì)賬 確保系統(tǒng)數(shù)據(jù)與支付通道一致,補(bǔ)上 “最后一道資金安全防線(xiàn)”,符合金融級(jí)數(shù)據(jù)可靠性要求。
- 容災(zāi)與風(fēng)控:應(yīng)對(duì)極端場(chǎng)景通過(guò) 多通道容災(zāi)、降級(jí)策略 應(yīng)對(duì)通道故障;用多層風(fēng)控模型識(shí)別欺詐交易,同時(shí)建立完善的退款機(jī)制,兼顧 “用戶(hù)體驗(yàn)” 與 “資金安全”。
同時(shí),隨著移動(dòng)支付場(chǎng)景的拓展(如跨境支付、刷臉支付),系統(tǒng)還需應(yīng)對(duì)新的挑戰(zhàn):跨境支付要兼容不同國(guó)家的貨幣轉(zhuǎn)換、支付通道與監(jiān)管規(guī)則;刷臉支付則需平衡 “識(shí)別效率” 與 “身份核驗(yàn)準(zhǔn)確性”,避免冒用他人面容支付。
這就要求技術(shù)團(tuán)隊(duì)既要深耕現(xiàn)有體系的穩(wěn)定性,也要持續(xù)跟進(jìn)新技術(shù)、新場(chǎng)景,讓支付系統(tǒng)在 “安全” 與 “體驗(yàn)” 之間找到最優(yōu)解。
下次再遇到支付 “轉(zhuǎn)圈圈”,你或許能猜到:可能是 API 網(wǎng)關(guān)限流了,也可能是支付通道臨時(shí)波動(dòng) —— 而這背后,是無(wú)數(shù)技術(shù)人在為 “每一筆錢(qián)的安全流轉(zhuǎn)” 保駕護(hù)航。




































