在支付系統(tǒng)改進(jìn)中况芒,我們對(duì)原有系統(tǒng)做了整體的評(píng)估惜纸,選擇支付網(wǎng)關(guān)作為入手點(diǎn)來(lái)進(jìn)行微服務(wù)架構(gòu)的改進(jìn)。這里詳細(xì)介紹我們針對(duì)該模塊的改進(jìn)過(guò)程绝骚,供參考耐版。
原有系統(tǒng)情況
早期啟動(dòng)的時(shí)候,對(duì)接的支付渠道不多压汪,所有支付渠道和支付網(wǎng)關(guān)都實(shí)現(xiàn)在一個(gè)項(xiàng)目中粪牲,部署在一起。其中支付網(wǎng)關(guān)是整個(gè)項(xiàng)目的核心和入手點(diǎn)止剖。它為各個(gè)業(yè)務(wù)方提供支付全流程的調(diào)用接口腺阳,簽約、代扣穿香、支付亭引、驗(yàn)證,都是通過(guò)這個(gè)接口來(lái)實(shí)現(xiàn)的皮获。整個(gè)系統(tǒng)使用SSH框架焙蚓,架構(gòu)如下:
業(yè)務(wù)流程如下:
當(dāng)接口被調(diào)用時(shí), 首先執(zhí)行參數(shù)校驗(yàn)洒宝,確認(rèn)輸入的參數(shù)的合法性购公,驗(yàn)證參數(shù)簽名是否正確。確認(rèn)過(guò)程包括調(diào)用賬戶(hù)雁歌、用戶(hù)宏浩、支付方式、路由等服務(wù)來(lái)驗(yàn)證用戶(hù)ID将宪、賬戶(hù)绘闷、支付卡號(hào)橡庞、支付金額等參數(shù)。
根據(jù)輸入的支付方式印蔗,調(diào)用支付路由服務(wù)扒最,獲取對(duì)應(yīng)的支付渠道。
調(diào)用風(fēng)控接口進(jìn)行驗(yàn)證华嘹,如果有交易風(fēng)險(xiǎn)吧趣,則阻斷本次交易。
生成交易記錄耙厚;
調(diào)用支付渠道提供的服務(wù)執(zhí)行支付强挫。
根據(jù)支付結(jié)果,更新訂單狀態(tài)薛躬;
通知商戶(hù)訂單執(zhí)行結(jié)果俯渤。
在實(shí)現(xiàn)上,原有系統(tǒng)實(shí)現(xiàn)的類(lèi)結(jié)構(gòu)圖如下:
采用SSH架構(gòu)型宝,支付網(wǎng)關(guān)實(shí)現(xiàn)為一個(gè)大Apache Struts Action類(lèi)八匠,和支付相關(guān)的所有業(yè)務(wù)邏輯都實(shí)現(xiàn)在一個(gè)項(xiàng)目中。
支付網(wǎng)關(guān)承載大量的功能趴酣,實(shí)際上梨树,它是將API網(wǎng)關(guān)和業(yè)務(wù)邏輯都混在在一起實(shí)現(xiàn)。 簽約岖寞、支付抡四、代扣、驗(yàn)證仗谆,都在這一個(gè)類(lèi)中實(shí)現(xiàn)指巡,代碼行數(shù)超過(guò)1000行,邏輯十分復(fù)雜胸私。
除了風(fēng)控是進(jìn)程外調(diào)動(dòng)厌处,其他的服務(wù)都是進(jìn)程內(nèi)調(diào)用,通過(guò)springframework來(lái)管理各個(gè)service岁疼。
最終落地調(diào)用的支付渠道,是通過(guò)抽象的接口來(lái)對(duì)網(wǎng)關(guān)封裝渠道的差異缆娃。
在這個(gè)系統(tǒng)中對(duì)接了有30多個(gè)渠道捷绒,類(lèi)規(guī)模達(dá)到2000個(gè)。隨著業(yè)務(wù)發(fā)展贯要,問(wèn)題越來(lái)越多暖侨。高峰期同時(shí)有5個(gè)渠道在并行開(kāi)發(fā),還有大量的其他渠道對(duì)接問(wèn)題需要修復(fù)崇渗。多個(gè)人同時(shí)修改一個(gè)項(xiàng)目代碼導(dǎo)致版本控制的工作驟增字逗。上線(xiàn)頻發(fā)引起服務(wù)中斷也讓業(yè)務(wù)方很不滿(mǎn)京郑。對(duì)支付網(wǎng)關(guān)的改進(jìn)是一個(gè)循序漸進(jìn)的過(guò)程。這里參考Arun Gupta的微服務(wù)六種設(shè)計(jì)模式葫掉,來(lái)描述我們所做的改進(jìn)些举。
新網(wǎng)關(guān)設(shè)計(jì) (Chain Pattern)
為了分解舊網(wǎng)關(guān)的功能, 我們?cè)O(shè)計(jì)了新的網(wǎng)關(guān)俭厚。在處理流程上户魏,將其分為三個(gè)步驟,采用的是chain模式挪挤。
鏈?zhǔn)侥J降鸪螅缟蠄D所示,它調(diào)用服務(wù)A來(lái)獲取結(jié)果扛门,而服務(wù)A是通過(guò)服務(wù)B來(lái)交互鸠信,B則會(huì)和C有交互。 整個(gè)過(guò)程類(lèi)似同步的HTTP請(qǐng)求论寨、響應(yīng)處理症副。 這其中每個(gè)階段的調(diào)用,都是阻塞式的同步調(diào)用政基。每一步都會(huì)增加一些業(yè)務(wù)邏輯處理贞铣。
原支付網(wǎng)關(guān)難以維護(hù)的一個(gè)重要原因是其所承載的功能過(guò)多。我們首先根據(jù)用戶(hù)的使用場(chǎng)景沮明,將支付網(wǎng)關(guān)承載的功能辕坝,按照支付產(chǎn)品來(lái)進(jìn)行切分。 支付產(chǎn)品包括快捷支付荐健、網(wǎng)銀支付酱畅、外卡支付等。 不同的產(chǎn)品江场,其對(duì)應(yīng)的操作所使用的參數(shù)和流程也不一樣纺酸。以快捷產(chǎn)品為例, 新網(wǎng)關(guān)接收到請(qǐng)求后址否,根據(jù)用戶(hù)所選擇的支付類(lèi)型餐蔬,分發(fā)到快捷支付產(chǎn)品接口∮痈剑快捷支付產(chǎn)品接口調(diào)用工行借記卡通道來(lái)執(zhí)行支付樊诺,通道最終落地到工行接口的調(diào)用來(lái)實(shí)現(xiàn)支付。 支付操作完成后音同,工行接口通知到通道词爬,通道通知到產(chǎn)品,最終逆向傳遞到網(wǎng)關(guān)接口权均,并最終發(fā)送給調(diào)用方顿膨。 在這里面锅锨,支付網(wǎng)關(guān)負(fù)責(zé)分發(fā)、驗(yàn)簽等基本功能恋沃,支付產(chǎn)品負(fù)責(zé)參數(shù)校驗(yàn)必搞、路由、生成交易記錄等功能芽唇。最終的支付操作是落地到支付渠道去執(zhí)行顾画。
網(wǎng)關(guān)拆分(Proxy Pattern)
如上所述,支付網(wǎng)關(guān)按照使用場(chǎng)景進(jìn)行拆分匆笤。我們采用完善一個(gè)研侣、接入一個(gè)的原則,在保留舊網(wǎng)關(guān)的功能的同時(shí)炮捧,開(kāi)發(fā)完善新的網(wǎng)關(guān)和支付產(chǎn)品庶诡。等所有流量都打到新網(wǎng)關(guān)上去之后,舊網(wǎng)關(guān)就直接廢棄了咆课。為了達(dá)到這個(gè)目標(biāo)末誓,我們引入了代理模式:
代理模式和聚合模式類(lèi)似,不同點(diǎn)在于书蚪,它會(huì)根據(jù)業(yè)務(wù)邏輯需要僅選擇一個(gè)微服務(wù)來(lái)調(diào)用喇澡。微服務(wù)中,我們經(jīng)常會(huì)用代理模式來(lái)構(gòu)建API網(wǎng)關(guān)殊校。
我們首先按照所支持的支付方式晴玖,對(duì)支付網(wǎng)關(guān)做分解,拆分為為網(wǎng)銀为流、快捷呕屎、話(huà)費(fèi)、賬戶(hù)敬察、外卡秀睛、虛幣等支付產(chǎn)品。新網(wǎng)關(guān)接口模塊是一個(gè)proxy莲祸,本身并未實(shí)現(xiàn)任何業(yè)務(wù)邏輯蹂安,它的工作是將用戶(hù)請(qǐng)求發(fā)送給合適的支付產(chǎn)品去處理。如果這個(gè)產(chǎn)品還沒(méi)有實(shí)現(xiàn)虫给,則將其轉(zhuǎn)發(fā)到老網(wǎng)關(guān)去執(zhí)行藤抡。這樣帶來(lái)的好處是,我們不需要對(duì)老網(wǎng)關(guān)做任何改動(dòng)抹估。而且,如果某個(gè)支付產(chǎn)品在重構(gòu)過(guò)程中出現(xiàn)問(wèn)題弄兜,我們可以很快切回到老網(wǎng)關(guān)去药蜻。
支付產(chǎn)品 (Aggregator Pattern)
支付產(chǎn)品是對(duì)原有支付網(wǎng)關(guān)的業(yè)務(wù)流程實(shí)現(xiàn)的一個(gè)重構(gòu)瓷式,按照各個(gè)支付產(chǎn)品所支持的功能以及流程來(lái)簡(jiǎn)化原混合在一起的設(shè)計(jì)。比如快捷支付需要簽約和支付语泽,而網(wǎng)銀支付則不需要簽約贸典。 在支付產(chǎn)品本身的實(shí)現(xiàn)上,我們使用的是聚合模式踱卵。
聚合是最常見(jiàn)的微服務(wù)設(shè)計(jì)模式廊驼,它是一個(gè)高層次的微服務(wù)組合,供其他服務(wù)調(diào)用惋砂。 在這種情況下妒挎,聚合器會(huì)從其他的微服務(wù)中收集數(shù)據(jù),做業(yè)務(wù)邏輯處理西饵,然后發(fā)布成一個(gè)服務(wù)終端酝掩。其他有需要的服務(wù)可以調(diào)用它。 聚合器設(shè)計(jì)的要點(diǎn)是要遵循DRY(Don’t Repeat Yourself)原則眷柔。如果有多個(gè)服務(wù)需要訪(fǎng)問(wèn)A期虾,B,C服務(wù)驯嘱,那建議的處理方式是镶苞,針對(duì)這些使用,提煉一個(gè)處理邏輯出來(lái)鞠评,將A茂蚓、B、C封裝為一個(gè)新的服務(wù)谢澈,這個(gè)服務(wù)可以獨(dú)立的演化煌贴。
支付產(chǎn)品中調(diào)用的各個(gè)服務(wù),包括支付方式管理锥忿, 支付服務(wù)管理牛郑,支付路由管理、支付記錄管理等敬鬓,都被重構(gòu)為微服務(wù)淹朋,在支付產(chǎn)品的實(shí)現(xiàn)中,通過(guò)Aggregator 模式進(jìn)行調(diào)用钉答。
在支付產(chǎn)品的實(shí)現(xiàn)流程中础芍,首先需要對(duì)參數(shù)進(jìn)行校驗(yàn),校驗(yàn)成功后数尿,調(diào)用風(fēng)控檢查該交易是否可以放行仑性。這兩個(gè)操作,在處理上可以并行右蹦,使用的是分支模式。
分支模式是聚合模式的擴(kuò)展,可以允許同時(shí)調(diào)用兩個(gè)或者更多的微服務(wù)轨蛤。
如上,采用分支模式豹储, 使得數(shù)據(jù)校驗(yàn)和風(fēng)控可以并發(fā)執(zhí)行。由于風(fēng)控相對(duì)耗時(shí)較長(zhǎng)淘这,而訂單中需要校驗(yàn)的數(shù)據(jù)較多剥扣,這兩個(gè)操作有必要并發(fā)執(zhí)行。
支付通道 (Aggregator Pattern)
支付路由根據(jù)用戶(hù)選擇的支付方式對(duì)支付通道進(jìn)行篩選铝穷,選取合適的支付通道钠怯。支付產(chǎn)品調(diào)用該通道的接口來(lái)最終落地完成支付服務(wù)。 每個(gè)支付通道對(duì)接也被實(shí)現(xiàn)為微服務(wù)氧骤,在支付產(chǎn)品中調(diào)用呻疹。
通知商戶(hù) (Asynchronous Messaging Pattern)
支付產(chǎn)品執(zhí)行的最后一個(gè)步驟是通知調(diào)用方支付的結(jié)果。 原系統(tǒng)實(shí)現(xiàn)是將這個(gè)步驟耦合在原有代碼中筹陵,容易受到調(diào)用方接口的穩(wěn)定性的影響刽锤。 為此,這里采用異步消息的模式來(lái)進(jìn)行重構(gòu):
異步消息一般用于對(duì)流程中可以異步執(zhí)行的操作做分解朦佩,將它從原流程中分離出來(lái)并思,通過(guò)消息機(jī)制來(lái)異步執(zhí)行。 支付產(chǎn)品在完成支付服務(wù)后语稠,發(fā)出消息到訂單消息隊(duì)列中宋彼。 商戶(hù)回調(diào)處理程序接收到消息后,調(diào)用商戶(hù)回調(diào)接口告知支付結(jié)果仙畦。 此外输涕,風(fēng)控、BI系統(tǒng)等慨畸,也可以使用這個(gè)消息來(lái)同步訂單數(shù)據(jù)莱坎。
總結(jié)
這里簡(jiǎn)單介紹了支付網(wǎng)關(guān)重構(gòu)的過(guò)程,以及如何使用微服務(wù)設(shè)計(jì)模式寸士。 當(dāng)然檐什,這里我們也忽略了很多細(xì)節(jié),比如支付網(wǎng)關(guān)所依賴(lài)的基礎(chǔ)服務(wù)的開(kāi)發(fā)弱卡。 最終的支付網(wǎng)關(guān)的架構(gòu)乃正,參考《支付網(wǎng)關(guān)設(shè)計(jì)》一文。這里涉及到的支付路由婶博、支付記錄瓮具、支付風(fēng)控等模塊的設(shè)計(jì),后續(xù)也會(huì)在本博客中做介紹。 微服務(wù)化改造并不難搭综,需要的是對(duì)原有系統(tǒng)有深入的了解垢箕,然后運(yùn)用各種模式來(lái)拆分划栓,庖丁解牛兑巾。拆分的每一步都需要注意,在設(shè)計(jì)上忠荞,需要考慮一旦出現(xiàn)問(wèn)題即可回滾蒋歌。
感謝您對(duì)本文的關(guān)注,如需要及時(shí)收到鳳凰牌老熊的最新作品委煤,或者有相關(guān)問(wèn)題探討堂油,請(qǐng)掃碼關(guān)注“鳳凰牌老熊”的微信公眾號(hào),在公眾號(hào)里留言或者回復(fù)碧绞,可以盡快處理府框,謝謝。
本文來(lái)自 微信公眾號(hào)“鳳凰牌老熊”讥邻。