一个细节翔实、可供参考的支付体系架构演进实例--转
注:本文整理自美麗聯(lián)合集團資深工程師陳宗在 ArchSummit 深圳 2017 上的演講,原題為:《支付體系架構(gòu)與實踐》。
上篇:支付體系架構(gòu)演進
在過去 4 年的時間里,作為面向億級用戶的大型時尚消費平臺,美聯(lián)集團歷經(jīng)著高速的業(yè)務(wù)增長和快速的業(yè)務(wù)演進。而其中最重要的基礎(chǔ)業(yè)務(wù)平臺,美聯(lián)支付如何穩(wěn)打穩(wěn)扎、平滑演進,快速適應(yīng)并高效支持著業(yè)務(wù)的復(fù)雜變化。我們從單一功能到完整體系、從臃腫單體 Php 演變?yōu)楦咝阅芨呖煽靠缮炜s的分布式服務(wù)架構(gòu),于 16 年快速融合美麗說和淘世界支付體系,并在歷年大促中保持無故障的出色表現(xiàn),逐漸摸索出適應(yīng)全集團復(fù)雜業(yè)務(wù)形態(tài)和變化的支付平臺架構(gòu)。
支付系統(tǒng) 1.x
13 年下半年的時候,蘑菇街從導(dǎo)購平臺轉(zhuǎn)為電商平臺。為了支撐電商業(yè)務(wù),我們快速實現(xiàn)了第一代的支付系統(tǒng)。當(dāng)時蘑菇街的業(yè)務(wù)簡單、玩法單一。如圖 1.1 所示,第一代的支付系統(tǒng)只包含了支付最核心功能,從而盡快的支撐業(yè)務(wù)。在這期間,我們實現(xiàn)了面向業(yè)務(wù)的收銀臺、支付模塊,面向資金端的賬務(wù)模塊,以及與三方支付對接的渠道網(wǎng)關(guān)。
1.x 支付系統(tǒng)架構(gòu)
隨后的幾年,美聯(lián)的業(yè)務(wù)進入超高速的發(fā)展,電商交易、以及支付的業(yè)務(wù)復(fù)雜度劇增,玩法多變。同時,在經(jīng)歷數(shù)次大促之后,我們發(fā)現(xiàn),支付核心鏈路大促 QPS 峰值達到了日常的百倍以上。在這種情況下,我們其實遇到了蠻多的問題,以下分為三部分來說下我們當(dāng)時碰到的問題:
?業(yè)務(wù)問題
1.x 支付系統(tǒng)構(gòu)建的時候,支付系統(tǒng)設(shè)定了比如擔(dān)保交易、提現(xiàn)等支付交易表。但是隨著業(yè)務(wù)越來越復(fù)雜,我們加了越來越多的支付交易表,整個系統(tǒng)的架構(gòu)如同圖 1.2 所示的煙囪型架構(gòu)。當(dāng)時來一個業(yè)務(wù),我們加 1-N 張表。
煙囪型系統(tǒng)機構(gòu)
截止到 15 年底,整個支付系統(tǒng)存在這數(shù)十個支付交易表。這么多的表,側(cè)面反映了我們對支付業(yè)務(wù)并沒有做模型的抽象,只是在業(yè)務(wù)的野蠻生長下,不斷的應(yīng)對和接入。同時,在這種情況下,業(yè)務(wù)的邊界很模糊,經(jīng)常有業(yè)務(wù),一半的業(yè)務(wù)邏輯實現(xiàn)在業(yè)務(wù)方,一半的業(yè)務(wù)邏輯在支付方。
?系統(tǒng)問題
當(dāng)時我們整一個支付系統(tǒng)都在一個巨大無比的單體 php 應(yīng)用里。雖然系統(tǒng)在演進,也分出了不少的模塊,但是大家知道。在一個巨大的單體應(yīng)用里,比較容易出現(xiàn)各模塊的耦合,比如支付模塊調(diào)用了渠道網(wǎng)關(guān)模塊的一個內(nèi)部的方法等等。而另外一個,支付團隊的幾十號同學(xué)每天都在一個應(yīng)用里面開發(fā) & 發(fā)布。任何一個地方跪了,都有可能讓支付系統(tǒng)崩潰,穩(wěn)定性非常低。
最后,電商平臺的特性,決定了我們必須要不斷的提升支付系統(tǒng)的性能。在 15 年的時候,我們對支付系統(tǒng)的 DB 進行了基于模塊的垂直拆分,如下圖所示。以用于提升系統(tǒng)容量。但這種情況下,我們還是碰到到性能瓶頸。
舉個例子:15 年雙十一,當(dāng)時定下來系統(tǒng)能夠支持 2kqps 的峰值支付性能。但在數(shù)輪鏈路壓測之后,即時我們對 DB 進行了垂直拆分,并用了最好硬件 fushion IO, 但是我們發(fā)現(xiàn)系統(tǒng)僅能支撐大概 1800qps 左右的支付。當(dāng)時其實是比較絕望的,我清楚的記得在 15 年的 10 月底,11 月初的很多白天黑夜,緊急對支付系統(tǒng)的擔(dān)保交易下單進行了改造,添加了一系列的緩存,最終性能勉強能夠達標(biāo)。
支付系統(tǒng) DB 垂直拆分
?資金問題
第一代的支付系統(tǒng)中,我們對各個業(yè)務(wù)方的支付接入,并未提供任何的授權(quán)和鑒權(quán)。也就是說任何系統(tǒng)、任何團隊都有可能調(diào)用支付系統(tǒng)接口進行資金操作,當(dāng)時支付有一個萬能的轉(zhuǎn)賬接口,業(yè)務(wù)方接入確實很方便,但其實埋了蠻多坑。雖然當(dāng)時我們支付的業(yè)務(wù)做了日志記錄,但是在數(shù)據(jù)庫里面,我們并未能區(qū)分來源的業(yè)務(wù)、哪種操作,導(dǎo)致了我們對各項業(yè)務(wù)的流水、收入、支出難以統(tǒng)計和核算。
另外我們當(dāng)時也碰到了數(shù)據(jù)一致性挑戰(zhàn)。當(dāng)時支付系統(tǒng)僅有內(nèi)外部渠道對賬,而對內(nèi)部的業(yè)務(wù)數(shù)據(jù),并沒有做好對賬事宜,經(jīng)常出現(xiàn)用戶反饋異常問題,然后我們才能知曉。
支付體系 2.0 架構(gòu)實踐
1.x 的支付系統(tǒng)中,其實我們碰到了很多的問題,痛定思痛,我們決心對支付體系做一次架構(gòu)升級。那么,怎么去做支付體系的架構(gòu)升級呢?,我們從兩個方面來進行架構(gòu)升級梳理:
巨大的單體應(yīng)用必須得拆分,在拆分之前,我們需要確定業(yè)務(wù)、系統(tǒng)邊界,對支付業(yè)務(wù)進行建模。
構(gòu)建完整的資金核算體系,以達到能夠清晰的知曉各類業(yè)務(wù)的流水、收入、支出等。
拆分系統(tǒng)邊界
那么單體應(yīng)用拆分之前,那么如何確定邊界? 從三個維度對邊界進行了拆分:
基于業(yè)務(wù),拆分為面向支付業(yè)務(wù),面向資金核算體系
基于場景,例如依據(jù)支付流程等
基于技術(shù)實現(xiàn),比如出于對系統(tǒng)的性能考慮等
我們對支付體系里面的核心系統(tǒng)拆分為:收銀臺、交易核心、支付核心、網(wǎng)關(guān)、賬務(wù)、會計、清算、合規(guī)等。下圖是對核心支付鏈路流程示意:
核心支付鏈路流程
支付體系 2.0 整體架構(gòu)
得益于蘑菇街強大的基礎(chǔ)平臺 & 中間件系統(tǒng),比如 RPC 服務(wù)框架 Tesla,數(shù)據(jù)庫中間件 Raptor,可靠的消息中間件 Corgi,數(shù)據(jù)庫事件變更中間件 Pigeon,數(shù)據(jù)配置推送平臺 metabase,分布式緩存 kvstore 等等。我們在 15 年第四季度,對支付系統(tǒng)做了整體的服務(wù)化拆分。大家可以看下圖支付體系 2.0 的整體架構(gòu)圖:
支付體系 2.0 整體架構(gòu)圖
如圖所示,我們大致介紹下各系統(tǒng)的功能:
面向支付業(yè)務(wù)拆分為:收銀臺、交易核心、支付核心、渠道網(wǎng)關(guān)
面向資金核算拆分為:賬務(wù)、會計、清算、合規(guī)
其他基礎(chǔ)服務(wù),比如支付會員服務(wù),支付風(fēng)控和支付對賬等。
支付體系 2.0 系統(tǒng)拆分
上文中呈現(xiàn)了支付體系 2.0 的整體架構(gòu),我們接下來對各核心系統(tǒng)的拆分和實現(xiàn)進行介紹:
?交易核心
從剛才的支付鏈路可以看出,交易核心作為支付系統(tǒng)入口,對接上層的業(yè)務(wù)系統(tǒng)。在 15 年底,支付系統(tǒng)有著數(shù)十張的支付交易表,如何抽取合適業(yè)務(wù)模型,是我們最重要的事情。另外,為了數(shù)據(jù)的統(tǒng)一性,我們對分散數(shù)十張的支付交易表進行了多表聚合,以及訂單關(guān)聯(lián)。同時,支付的接入管控也放在了交易核心實現(xiàn),整體的架構(gòu)如下圖所示:
交易核心架構(gòu)圖
基礎(chǔ)交易類型抽象
交易核心里面如何做基礎(chǔ)交易類型的模型抽象?主要還是基于對支付的理解,如圖 2.4 所示的例子中,電商交易的預(yù)售 和 廣告營銷的購買,都是從用戶購買直接到收款方。那么我們可以抽象為即時交易,即直接從 a 用戶到 b 用戶的支付行為。
基礎(chǔ)交易類型抽象
基于對業(yè)務(wù)的分析理解,我們對交易核心的業(yè)務(wù)進行了抽象,抽象為 10 多種交易類型:
-
大家比較熟悉的:擔(dān)保交易、即時交易、充值、提現(xiàn)、擔(dān)保退款、即時退款、轉(zhuǎn)賬等。
-
以及不太常見的:提現(xiàn)退票、退款退單、異常退款、充值退款等。
多表聚合 & 訂單關(guān)聯(lián)
我們對數(shù)十張的支付交易表進行多表聚合,是基于一張主表來實現(xiàn)。而在這種情況下,業(yè)務(wù)訂單如何保持唯一是我們需要考慮的事情。考慮到需要對上層業(yè)務(wù)的極少侵入性,在新設(shè)計的支付交易表中,有專門的字段用于做唯一鍵約束:
業(yè)務(wù)識別碼 + 業(yè)務(wù)訂單號 來進行訂單唯一約束。
另外,做了一個小功能,任何訂單都可以追溯到初始單,如下圖為例,擔(dān)保交易下的所有的單子都可以找到,同時也能追溯到初始的訂單。
擔(dān)保交易訂單關(guān)聯(lián)
支付管控
鑒于交易核心為支付平臺的入口,針對 1.x 支付系統(tǒng)中支付接入無授權(quán)問題,我們也在交易核心里面做了支付接入的管控,授權(quán) & 鑒權(quán)。為任何一個接入支付的業(yè)務(wù)分配唯一的業(yè)務(wù)標(biāo)識碼 & 授權(quán)的 token。從而使得業(yè)務(wù)在支付接入時,須帶上 token & 加鹽過的加密數(shù)據(jù)傳入。
?支付核心
我們將 1.x 支付系統(tǒng)里面的支付模塊,切分兩層,交易核心 & 支付核心。交易核心面向上游業(yè)務(wù),支付核心面向支付系統(tǒng)內(nèi)部。
支付核心整體架構(gòu)如圖 2.6,我們對支付核心同樣進行了支付類型的抽象:充值、提現(xiàn)、退款、轉(zhuǎn)賬四類,任何一個交易核心訂單請求,都能被四種基礎(chǔ)支付類型組合進而完成支付行為。另外,支付核心需要基于系統(tǒng)、用戶指令等完成各種各樣的支付行為。按照簡單的做法,我們可以在不同的分支上實現(xiàn)各式的支付行為,但是這樣可能會導(dǎo)致支付行為的耦合,以及支付的復(fù)雜邏輯判斷。基于這種原因,我們對支付工具進行組件化拆分,封裝為數(shù)十種支付工具,通過支付編排來執(zhí)行支付行為。
支付核心架構(gòu)圖
支付行為編排
支付交易訂單通過支付規(guī)則生成具體的支付請求(即支付核心記錄),支付請求通過支付指令編排規(guī)則,獲取一組支付工具包。通過支付執(zhí)行器完成對支付工具的調(diào)用執(zhí)行。這樣的封裝,我們可以實現(xiàn)插件式開發(fā),以及可支付規(guī)則可配置化,繼而讓支付核心內(nèi)部的支付工具互不影響 & ?系統(tǒng)簡化。整個編排過程如下圖所示:
支付行為編排
異常處理機制
支付核心有一個比較重要的功能,是如何對支付異常進行處理,支付過程比如重復(fù)支付、部分支付、金額不一致、其他異常全額退款等等異常,都需要做異常的退款。
如圖 2.8 以部分支付為例,我們做了一個異常管理組件來處理這種異常,在網(wǎng)關(guān)支付 + 紅包 + 優(yōu)惠券組合支付中,對每次的支付都進行上報。紅包支付、優(yōu)惠券支付,都成功上報,而對于網(wǎng)關(guān)支付異常時,也做異常上報機制。通過異常管理組件對部分支付成功的行為進行反向異常退款。
部分支付異常退款
?渠道網(wǎng)關(guān)
我們對渠道網(wǎng)關(guān)系統(tǒng)進行拆分,渠道網(wǎng)關(guān)接受來自支付核心的支付請求,與三方支付進行交互。
網(wǎng)關(guān)系統(tǒng)同樣抽象了基礎(chǔ)服務(wù)類型:支付、退款、提現(xiàn)、簽約、查詢等。同時,為了性能考慮,網(wǎng)關(guān)系統(tǒng)切分為兩個子系統(tǒng),網(wǎng)關(guān)核心 & 網(wǎng)關(guān)前置:
網(wǎng)關(guān)核心負責(zé)渠道路由、渠道訂單的管理、以及渠道的分組。
網(wǎng)關(guān)前置負責(zé)渠道適配、報文轉(zhuǎn)換、以及外部通訊。
整體架構(gòu)如下圖所示
渠道網(wǎng)關(guān)整體架構(gòu)圖
?資金核算體系
資金核算體系主要由賬務(wù)系統(tǒng)、會計系統(tǒng)、清算系統(tǒng) 和合規(guī)系統(tǒng)組成,整體架構(gòu)如下圖所示:
支付核算體系
-
賬務(wù)系統(tǒng):由支付核心驅(qū)動,記錄管理賬戶信息,直接反應(yīng)用戶的賬戶余額和資金變更明細。
-
會計系統(tǒng):對業(yè)務(wù)運轉(zhuǎn)信息進行管理、核查、披露。 展現(xiàn)資金的來龍去脈。
-
清算系統(tǒng):由支付核心驅(qū)動,實現(xiàn)機構(gòu)間資金關(guān)系應(yīng)收應(yīng)付的主被動清算以及資金劃撥。
-
合規(guī)系統(tǒng):基于支付數(shù)據(jù),向資金監(jiān)管方同步交易信息流 & 資金流,從而契合央行合規(guī)監(jiān)管要求。
截止目前,我們對支付體系的面向業(yè)務(wù)的系統(tǒng) & 資金核算體系進行了介紹。
統(tǒng)一平臺業(yè)務(wù)上下文
1.x 支付系統(tǒng)單體應(yīng)用通過確定系統(tǒng)邊界、業(yè)務(wù)建模拆分之后,整個支付平臺被拆分幾十個服務(wù),而如何保障在服務(wù)間流轉(zhuǎn)業(yè)務(wù)信息不被丟失,是我們需要考慮的問題。就好比如何讓各個系統(tǒng)交互時都講普通話,而不是講方言。針對這個問題,我們做了平臺統(tǒng)一上下文的要素信息(唯一業(yè)務(wù)標(biāo)識碼),在整個支付平臺鏈路中全程傳遞,具體要素如下:
-
商戶:諸如 mgj 交易 & mls 交易等。
-
訂單類型:基于交易核心的業(yè)務(wù)類型,諸如擔(dān)保交易、即時交易、轉(zhuǎn)賬、提現(xiàn)等
-
訂單場景:諸如電商預(yù)售、營銷廣告購買等
-
支付機構(gòu):諸如支付寶、微信等
通過統(tǒng)一平臺業(yè)務(wù)上下文,我們能夠在任何一個系統(tǒng)里面清晰看出是哪種業(yè)務(wù),在哪種場景下,使用哪個渠道做了什么事情。
直面數(shù)據(jù)一致性挑戰(zhàn)
在單體應(yīng)用服務(wù)拆分之后,我們碰到了更加嚴峻的數(shù)據(jù)一致性挑戰(zhàn),系統(tǒng)間交互異常、無分布式事務(wù)的情況下,數(shù)據(jù)不一致的情況出現(xiàn)的概率還是非常大。
那么我們是如何解決數(shù)據(jù)一致性問題的?總結(jié)下來有三個方面:
?CAS
在整個支付平臺中,我們對可能有并發(fā)沖突的系統(tǒng)做了 CAS 樂觀鎖 ,以交易核心、支付核心為例,通過狀態(tài)的 CAS 樂觀鎖防止并發(fā),如下所示:
update PayOrder set status='complete' where id=1 and status='process'
同時,也做了基于 KVstore 的分布式緩存鎖來防止多數(shù)據(jù)之間的并發(fā)問題,例如解決重復(fù)支付問題等。
?接口冪等 & 異常補償
我們要求整個支付體系中的所有服務(wù),涉及數(shù)據(jù)變更的接口都要求保持接口冪等。通過全鏈路的冪等,使得重試成為了可能。
在諸如服務(wù)超時、網(wǎng)絡(luò)異常的情況下,我們做了兩種不同的異常補償:基于消息中間件 Corgi 的準(zhǔn)實時補償 & 基于異常表的補償。
以支付回調(diào)鏈路為例,如下圖所示,渠道網(wǎng)關(guān)和支付核心之間的交互,使用的兩者補償?shù)姆绞健=灰缀诵?對電商交易的支付成功通知方式,我們使用異常表的補償,在 12 小時內(nèi)遞衰的通知 10 次等等。
支付回調(diào)補償機制
?完整對賬體系
在支付體系中,對賬是數(shù)據(jù)一致性的最后一道防護。對賬可分為兩部分:
內(nèi)外對賬,是 1.x 支付系統(tǒng)上線之后已經(jīng)實現(xiàn)該功能。確保美麗聯(lián)合集團支付數(shù)據(jù)與三方支付的數(shù)據(jù)保持一致。
內(nèi)部業(yè)務(wù)對賬,在 2.0 支付體系構(gòu)建過程中,我們做了一套內(nèi)部業(yè)務(wù)準(zhǔn)實時對賬系統(tǒng),用于核對整個平臺數(shù)據(jù)。
下面對內(nèi)部準(zhǔn)實時做簡單的介紹:
內(nèi)部準(zhǔn)實時對賬
如下圖所示,準(zhǔn)實時對賬平臺支持各種數(shù)據(jù)源的接入,目前基于系統(tǒng)解耦的考慮,我們更多的使用數(shù)據(jù)庫事件變更中間件 Pigeon 來接入對賬雙方的 binlog 數(shù)據(jù),通過配置的規(guī)則 或者自定義的轉(zhuǎn)換邏輯來進行雙方的模型轉(zhuǎn)換,從而通過對賬核心進行數(shù)據(jù)的核對。目前通過該系統(tǒng),我們可以在 5-25min 之內(nèi),發(fā)現(xiàn)異常數(shù)據(jù)。目前支付核心鏈路全部接入,支付全平臺 95% 以上。同時由于對賬系統(tǒng)的普適性,目前已經(jīng)推廣至公司所有業(yè)務(wù)。
準(zhǔn)實時對賬平臺架構(gòu)圖
基于上述的這些手段,我們能夠保障支付系統(tǒng)數(shù)據(jù)的最終一致性。
療效?
那么通過對支付體系的升級架構(gòu),我們?nèi)〉昧四男┏晒?#xff1f;
快速支撐業(yè)務(wù)。之前在接入新的業(yè)務(wù)的時候,大概率需要新增交易表以及開發(fā)上線。目前在升級之后,我們基本上只需要進行接入配置即可。
16 年快速融合淘世界、美麗說支付系統(tǒng)。在融合的過程中,新版的支付系統(tǒng)能夠兼容當(dāng)時的淘世界 & 美麗說支付系統(tǒng),順利的完成了融合。
基于業(yè)務(wù)接入授權(quán)管控 以及平臺統(tǒng)一上下文,我們能夠?qū)I(yè)務(wù)進行細分,從而能夠?qū)Ω鳂I(yè)務(wù)的資金情況進行細分和準(zhǔn)確的核實。
通過合規(guī)系統(tǒng)的實現(xiàn),符合央行的資金監(jiān)管要求,為用戶、商戶提供了強有力的資金安全保障。
總結(jié)展望
通過對業(yè)務(wù)的梳理、系統(tǒng)邊界的拆分、業(yè)務(wù)建模等手段,我們完成了對支付體系 2.0 架構(gòu)升級,進而能夠?qū)I(yè)務(wù)提供更加高效、穩(wěn)定、專業(yè)的支撐。進一步的提升了資金的核算 & 管控能力。但是目前的支付平臺里,每個子系統(tǒng)中,或多或少的都存在著自己的配置系統(tǒng),雖然是基于公用的統(tǒng)一的平臺業(yè)務(wù)上下文,但是配置還是繁瑣。如何做到統(tǒng)一化配置也是我們后續(xù)考慮的重點。同時,目前平臺業(yè)務(wù)統(tǒng)一上下文的四要素是基于交易核心出發(fā),從目前的系統(tǒng)演化來看,我們需要繼續(xù)改進為更優(yōu)化的模型,以應(yīng)對后續(xù)更加復(fù)雜的各類業(yè)務(wù)。
下篇:容量提升
在對美聯(lián)支付系統(tǒng)升級到支付體系 2.0 之后(支付體系架構(gòu)演進)。那么我們針對電商平臺特性,比如大促時支付鏈路峰值為日常的百倍以上等等特性,又做了哪些性能和穩(wěn)定的提升?
下面我們以支付核心鏈路為例,談?wù)勅绾翁嵘Ц镀脚_的性能和穩(wěn)定性。
支付核心鏈路
性能提升
針對于電商特性,我們對支付平臺的性能提升主要是從以下幾個方面優(yōu)化:
-
核心鏈路分庫分表:全鏈路水平擴展
-
服務(wù)調(diào)用異步化
-
熱點賬戶問題優(yōu)化
-
事務(wù)切分
核心鏈路分庫分表:全鏈路水平擴展
目前所有的應(yīng)用服務(wù)都是無狀態(tài),理論上應(yīng)用服務(wù)可以做到無限擴展,目前最大的瓶頸是在 DB。性能容量的提升,關(guān)鍵在于 DB 的容量。基于這個原因,我們對整個平臺的 DB 做了水平的拆分。
在全平臺水平擴展的過程中,我們以核心鏈路為例,從交易核心、支付核心、賬務(wù)核心、渠道網(wǎng)關(guān)等系統(tǒng)全部做了數(shù)據(jù)庫的水平拆分。基于交易核心、支付核心、渠道網(wǎng)關(guān)等系統(tǒng),前面介紹過,我們抽象了各種基礎(chǔ)模型,數(shù)據(jù)都是基于一張主表存儲,因此水平拆分基于該主表即可。
得益于美聯(lián)自研的數(shù)據(jù)庫中間件 Raptor,我們實現(xiàn)鏈路的分庫分表。同時,也基于全局統(tǒng)一的 sequence 生成器,保持了所有分片內(nèi)的主鍵 id 唯一性。
支付核心鏈路分庫分表
服務(wù)調(diào)用異步化
支付體系 2.0 升級之后,單體應(yīng)用拆分為數(shù)十個服務(wù)。系統(tǒng)的拆分和服務(wù)化,其實帶來了更多的系統(tǒng)依賴。相對于之前的單體應(yīng)用,從方法級的調(diào)用方式變更為 RPC 服務(wù)調(diào)用,網(wǎng)絡(luò)耗時 & 同時網(wǎng)絡(luò)的穩(wěn)定性等因素也是需要考慮的問題。基于這些考慮,非強實時的服務(wù)調(diào)用,異步化是最佳的解耦方式。同樣,在核心鏈路里,我們也做了各種各樣的異步化優(yōu)化,進而提升整體的鏈路性能,滿足電商平臺獨有的性能特性要求。
我們從幾個點來看下如何對支付系統(tǒng)做異步處理:
?支付消息報
基于數(shù)據(jù)庫事件中間件 Pigeon & 消息隊列 Corgi,我們實現(xiàn)支付消息報。如圖 1.2 所示,支付消息報基于交易核心數(shù)據(jù),聚合支付核心的支付數(shù)據(jù),最終生成支付消息報。通過這種方式,將原本需要在交易核心或者支付核心調(diào)用下游業(yè)務(wù)方,或者下游業(yè)務(wù)方實時查詢的方式,轉(zhuǎn)變?yōu)橄掠螛I(yè)務(wù)方通過接受消息的推送來獲取數(shù)據(jù),從而達到了業(yè)務(wù)的解耦。同時,也簡化了業(yè)務(wù)方的數(shù)據(jù)獲取復(fù)雜度。
支付消息報架構(gòu)圖
目前支付消息報已經(jīng)接入了 10 多個業(yè)務(wù)場景,例如滿返,支付成功短信通知,風(fēng)控所需的支付數(shù)據(jù)等等,并在持續(xù)不斷的增加中。
?外部支付異步化
在外部支付中,經(jīng)常會碰到這種情況,需要服務(wù)方與第三方支付交互,獲取預(yù)支付憑證,如圖 1.3 所示。這種同步調(diào)用的情況下,由于需要跨外部網(wǎng)絡(luò),響應(yīng)的 RT 會非常長,可能會出現(xiàn)跨秒的情況。由于是同步調(diào)用,會阻塞整個支付鏈路。一旦 RT 很長且 QPS 比較大的情況下,服務(wù)會整體 hold 住,甚至?xí)霈F(xiàn)拒絕服務(wù)的情況。
同步調(diào)用三方支付
基于這個問題,我們對這種獲取預(yù)支付憑證的方式進行了改進,詳見下圖:
異步調(diào)用三方支付
通過獨立網(wǎng)關(guān)渠道前置服務(wù),將獲取的方式分為兩個步驟:
針對支付鏈路,只是請求到渠道前置拿到內(nèi)部的支付憑證就結(jié)束了。
針對外部請求,由渠道前置異步向三方支付發(fā)起請求。
那么基于這種方式,與三方支付的同步交互僅僅會阻塞渠道前置。密集型的 io & 低 cpu 系統(tǒng),渠道前置的并發(fā)值可以設(shè)置的非常大。
?異步并行
支付平臺服務(wù)化之后,核心鏈路上的服務(wù)多為 IO 密集型,這里我們以收銀臺渲染為例,見下圖。
串行模式下的收銀臺渲染
一次收銀臺渲染,串行的調(diào)用各個服務(wù)來進行用戶信息查詢 (RT T1)、額度查詢 (RT T2)、優(yōu)惠查詢 (RT T3),最終執(zhí)行渠道渲染 (RT T4),這種實現(xiàn)方式下
收銀臺的渲染 RT = sum(T1,T2,T3,T4)
但是收銀臺的渲染 RT 必須要這么久嗎?其實對于業(yè)務(wù)的分析,我們發(fā)現(xiàn)其實很多的服務(wù)調(diào)用無先后順序。用戶信息查詢、額度查詢、優(yōu)惠查詢這三個服務(wù)的調(diào)用其實無先后順序,那么我們基于 Tesla 服務(wù)框架的異步化服務(wù)調(diào)用,見下圖。
異步并行模式下的收銀臺渲染
基于異步并行的收銀臺渲染方式,將并行過程中的各服務(wù)化的耗時之和變更為耗時最長的一個服務(wù)的 RT。
收銀臺渲染 RT =sum(max(T1,T2,T3),T4)
?資金核算體系異步化
目前支付平臺里,資金核算體系各個子系統(tǒng):會計系統(tǒng)數(shù)據(jù)來源于賬務(wù)系統(tǒng),賬務(wù) 、清算 、合規(guī)數(shù)據(jù)來源于支付核心。那么,需要在支付核心鏈路執(zhí)行的時候同步調(diào)用賬務(wù) & 清算 & 合規(guī),賬務(wù)實時調(diào)用會計嗎?其實基于對資金業(yè)務(wù)的分析,會計、清算、合規(guī)屬于非強實時業(yè)務(wù),可以通過數(shù)據(jù)變更中間件 Pigeon 同步數(shù)據(jù),對這三個系統(tǒng)進行了解耦,如圖:
資金核算體系異步化架構(gòu)
清算、合規(guī)通過監(jiān)聽支付核心 DB 數(shù)據(jù)變更來獲取數(shù)據(jù),會計通過監(jiān)聽賬務(wù)的流水庫的數(shù)據(jù)變更來獲取數(shù)據(jù),從而對實時鏈路非強實時業(yè)務(wù)進行解耦。
熱點賬戶問題優(yōu)化
熱點賬戶應(yīng)該是每一個做支付的童鞋都會碰到的問題。美聯(lián)的支付系統(tǒng)里,存在這各種各樣的熱點賬戶,我們將之分為三類:
內(nèi)部戶:比如渠道的待清分賬號等
平臺戶:比如各種平臺的營銷的墊支戶等
大商家的熱點賬戶等。
每種熱點賬戶的業(yè)務(wù)屬性都不一樣,比如商家賬戶,我們不能延遲記賬等等。基于這些情況,我們對熱點賬戶問題優(yōu)化也基于類型:
內(nèi)部戶
針對于內(nèi)部戶,我們在賬務(wù)中不做內(nèi)部戶這邊的記賬,而是由會計通過另外一邊的賬務(wù)流水去補分錄。
平臺戶
針對于平臺戶,在賬務(wù)中做了異步記賬,通過定時匯總記賬即可。
大商家
比較難的是大商家的熱點問題,特別是在美聯(lián)這種沒有商家結(jié)算周期的情況下,每一筆的訂單狀態(tài)變更,都有可能涉及商家的賬戶資金變更。但是也有解決辦法。分析其業(yè)務(wù)場景,擔(dān)保入賬、擔(dān)保出賬 、傭金扣費等占用了絕大多數(shù)的商家賬戶操作。針對這塊我們分為兩個點來做優(yōu)化:
將商家擔(dān)保賬戶切換到平臺擔(dān)保戶,基于流水去統(tǒng)計商家擔(dān)保中的金額。這種情況下,擔(dān)保入賬和出賬的商家熱點問題可以解決。
第一點的優(yōu)化能夠解決擔(dān)保出入賬的賬務(wù)操作,但是扣費依舊會造成大量的熱點賬戶問題,對此我們做了一個排序的任務(wù),將扣費做到做到單商家串行 & 多商家并行。
基于上述的兩個優(yōu)化方案,我們解決了大商家熱點賬戶問題。
通過對三種類型的熱點賬戶優(yōu)化進行,能夠解決目前系統(tǒng)碰到的熱點賬戶問題。但是各種平臺戶的賬務(wù)流水會非常多,以擔(dān)保戶為例,每日的所有的出入擔(dān)保戶的流水,都會在這個賬戶之上,那么在分庫分表情況下,會出現(xiàn)平臺戶所在的單表巨大無比。在這里我們引入二級子賬戶概念,將內(nèi)部戶 & 平臺戶在賬務(wù)虛化成 N 個二級子賬戶,從而均勻的分散在各個分表里,進而解決了該問題。
賬務(wù)記賬事務(wù)切分
在支付核心鏈路里,我們對非強實時依賴的服務(wù)做了異步化的解耦,對熱點賬戶進行了優(yōu)化的處理。在賬務(wù)記賬的時候,我們從下面兩個問題考慮優(yōu)化點:
在賬務(wù)分庫分表的情況下,如何保證記賬是在事務(wù)里?
每次記賬的出賬 & 入賬是否可拆分?
基于這兩個問題,我們對記賬流程進行了事務(wù)的拆分,如圖所示:
賬務(wù)記賬事務(wù)拆分
出賬、入賬分離。出賬成功,則整體成功,入賬失敗可以異步補賬。
出賬 & 入賬 ,每個里面都做單邊賬、異步記賬等處理,整個支付核心鏈路唯一的一個事務(wù)就在于更新賬務(wù)余額 ?& 新增流水。
目前系統(tǒng)中,經(jīng)過這一系列的優(yōu)化,單次的記賬性能,基本上穩(wěn)定在 15ms 左右。
穩(wěn)定性提升
在上文中,我們主要針對于支付鏈路的性能做了各種各樣的性能提升。資金無小事,如何保證支付平臺的穩(wěn)定性,也是我們需要考慮的重點。我們從下面幾個維度來提升穩(wěn)定性。
監(jiān)控先行
做穩(wěn)定性之前,我們需要知道我們的系統(tǒng)運行情況,那么必須要做線上系統(tǒng)的監(jiān)控,對關(guān)鍵指標(biāo)進行管控,以支付核心鏈路為例,如圖:
核心鏈路監(jiān)控
如圖所示,我們監(jiān)控了核心鏈路的 qps、rt、并發(fā)量等,同時也基于支付核心,我們對依賴的服務(wù) qps、rt 進行監(jiān)控。另外,也對依賴的 DB & Cache 進行監(jiān)控。
通過在監(jiān)控大盤中配置關(guān)鍵指標(biāo),能夠比較清晰明了的看出目前核心鏈路線上運行情況。
分離核心鏈路
基于電商特性,我們對整個核心鏈路進行了剝離,如圖所示:
分離核心鏈路
對核心鏈路分離的過程中,我們對鏈路中的各個服務(wù)中切分為核心 & 通用服務(wù)。分離的做法其實有很多,比如基于 Tesla 服務(wù)框架提供的服務(wù)分組功能;比如將一個服務(wù)切分為兩個服務(wù):核心鏈路服務(wù)和通用查詢服務(wù)。
在核心鏈路分離之后,能夠確保在任何時候,核心鏈路不會受到其他通用業(yè)務(wù)的影響而導(dǎo)致出現(xiàn)穩(wěn)定性問題。
服務(wù)依賴梳理
目前在支付系統(tǒng)里,有著數(shù)十個服務(wù),如果不對服務(wù)依賴進行梳理,系統(tǒng)穩(wěn)定性會得不到保障。我們從下面幾點來梳理服務(wù)依賴:
梳理平臺中的強弱依賴,判定哪些是強依賴,哪些是弱依賴。
弱依賴做好降級和超時保護,比如收銀臺渲染是的白付美額度查詢,這種可以埋降級開關(guān) & 設(shè)置較短的超時時間。因為查不到額度,最多不能使用白付美支付,并不會有特別大的影響。
如果是強依賴,這個不能降級,怎么辦?需要對強依賴的服務(wù)提出服務(wù)的 SLA 治理,比如賬務(wù)記賬功能,我們會要求系統(tǒng)不能掛、rt 不能超過 20ms,qps 需要支撐 8k qps 等等,基于這個約定,做子服務(wù)的優(yōu)化。
降級、限流
限流是保護系統(tǒng)不掛的最后一道防線。
目前支付平臺里面,存在基于 RPC 服務(wù)框架 tesla 的粗粒度限流,可控制在服務(wù)級別和方法級別;基于 spirit 的細粒度限流降級系統(tǒng),我們可以在單個方法里面做限流降級功能個,如下圖所示,我們在擔(dān)保交易下單過程中,區(qū)分平臺來源,做到蘑菇街擔(dān)保交易流量 & 美麗說擔(dān)保交易流量。
spirit 限流模式
但是不得不說,單單的 qps 或者并發(fā)限流都不能完全的做好限流保護,需要兩者的相結(jié)合才能達到所需的效果。
另外一點,通過對服務(wù)的依賴梳理,我們在各種弱依賴的服務(wù)中埋了一些降級開關(guān)。通過自研的降級推送平臺,一旦依賴服務(wù)出現(xiàn)問題或者不可用,可以快速的對該服務(wù)進行降級操作。
壓測怎么做?
在對系統(tǒng)擴容,鏈路性能優(yōu)化之后,怎么檢測成果呢?
我們引入線上壓測系統(tǒng),通過分析業(yè)務(wù)場景,構(gòu)建與線上真實場景幾乎一致的測試模型。以支付鏈路為例,模型中以日常 & 大促的流量模型為基準(zhǔn),設(shè)計壓測模型。需要注意的是,壓測模型越與真實一致,壓測的效果越好,對系統(tǒng)把控越準(zhǔn)確。。
通過構(gòu)建線上數(shù)據(jù)影子庫,壓測產(chǎn)生的測試數(shù)據(jù),會全量寫入到影子庫中。通過影子庫,在復(fù)用線上正式業(yè)務(wù)一致的環(huán)境、部署、機器資源下,我們能夠做到壓測對正常業(yè)務(wù)無侵入,對系統(tǒng)做準(zhǔn)確的把脈。
線上業(yè)務(wù)也分為兩塊,一塊是單機性能壓測,主要是分析單機的性能水位和各項指標(biāo)。另外是鏈路壓測,主要驗證系統(tǒng)的穩(wěn)定性和服務(wù)短板。
通過壓測的結(jié)果,我們能夠?qū)χЦ镀脚_的性能 & 穩(wěn)定性短板的分析和加以改進,能夠不斷的提升系統(tǒng)的穩(wěn)定性,提升系統(tǒng)的容量。
療效?
那么,通過一系列的性能容量的提升,我們達到了什么效果?
平臺容量方面:在 16 年雙十一的大促壓測中,我們在鏈路 DB 都擴圍兩組的物理的機器情況下,支付穩(wěn)定在 3000QPS。由于目前沒有需求,我們未對 DB 的物理機器擴到極限,因此系統(tǒng)的極限性能不能完全確定,但是按照預(yù)估,理論上可支持 1w QPS 以上。
機器利用率上:相同的容量情況下,我們的應(yīng)用減少為原有的 1/3。
鏈路的性能上:如圖 4.1 所示,以擔(dān)保交易為例,交易核心的收單 rt 幾乎在 10ms,而收銀臺渲染在 50ms,支付請求在 50ms,支付回調(diào)在 80ms 左右。
核心鏈路服務(wù)性能
同時,基于性能和穩(wěn)定性的提升,我們做到了支付在歷次的大促中,保持無故障的記錄。
總結(jié)展望
在美聯(lián)支付系統(tǒng)中,上層支付業(yè)務(wù)面向電商平臺,針對電商特色做更多的業(yè)務(wù)支持。我們對平臺的性能容量尋找可改進的地方,比如 DB、Cache、IO、以及異步化,持續(xù)不斷去優(yōu)化。另外,資金無小事,如何提升支付系統(tǒng)的穩(wěn)定性也是重點考慮的方向。
轉(zhuǎn)載于:https://www.cnblogs.com/davidwang456/p/7550020.html
總結(jié)
以上是生活随笔為你收集整理的一个细节翔实、可供参考的支付体系架构演进实例--转的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 20个非常有用的Java程序片段--转
- 下一篇: 就是这么迅猛的实现搜索需求--转