<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          從無到有,支付路由系統(tǒng)升級打怪之路|原創(chuàng)

          共 3579字,需瀏覽 8分鐘

           ·

          2020-11-19 11:03

          轉(zhuǎn)自:程序通事


          Hello,大家好,我是樓下小黑哥~

          今天繼續(xù)分享支付系統(tǒng)相關(guān)的內(nèi)容,這次分享一下如何支付路由系統(tǒng)實(shí)現(xiàn)方式。

          其實(shí)這個話題去年也寫過,不過當(dāng)時沒啥閱讀量,這次就再次翻出來加工一下,炒下冷飯。

          支付路由系統(tǒng)

          提到路由,不免會想到網(wǎng)絡(luò)通信過程中起到數(shù)據(jù)包轉(zhuǎn)發(fā)的路由器。

          圖片來自網(wǎng)絡(luò)

          而我們今天講到支付路由系統(tǒng),也是起到類似的作用。路由系統(tǒng)本身并不處理具體業(yè)務(wù),它的作用就是將支付請求轉(zhuǎn)發(fā)底層支付通道。

          支付路由系統(tǒng)

          如上圖所示,支付系統(tǒng)接入層,接收到支付請求之后,經(jīng)過內(nèi)部運(yùn)算,最后將會通過路由系統(tǒng)轉(zhuǎn)發(fā)給具體底層的支付通道。

          另外,除了路由轉(zhuǎn)發(fā)功能以外,路由器一般還會有一些額外的功能,比如防火墻等。

          那我們其實(shí)也可以在支付路由系統(tǒng)加入額外功能,比如實(shí)時計算底層支付渠道的成功率,若低于一定的閾值,進(jìn)行報警并且將該渠道下線。

          這里需要說明一點(diǎn),這里的路由系統(tǒng)可以是一個應(yīng)用中子模塊,也可以是一個單獨(dú)子系統(tǒng)。

          為什么需要路由系統(tǒng)

          看到這里,可能會有一些小伙伴會思考,一定需要這個路由系統(tǒng)嗎?直接將請求發(fā)給支付通道不好嗎?

          答案當(dāng)然是可以的,如果當(dāng)前只對接「一兩個支付渠道」,這么做沒問題,并且也推薦這么做。

          這個階段由于業(yè)務(wù)量不大,支付系統(tǒng)可能只是一個單體應(yīng)用,或者也可能是其他應(yīng)用內(nèi)一個子模塊而已。

          那這個時候,業(yè)務(wù)很簡單,系統(tǒng)也很簡單,那我們不需要額外的路由系統(tǒng),增加系統(tǒng)復(fù)雜度。

          不過這樣的系統(tǒng)弊端也很明顯,如果后期再新增一個支付通道,我們需要再開發(fā)對接。

          另外由于所有實(shí)現(xiàn)都在一個系統(tǒng),假設(shè)系統(tǒng)應(yīng)用發(fā)生問題,那么就是大家一起「死」,這其實(shí)也是單體系統(tǒng)最大弊端。

          所以如果底層對接支付通道很多,像一般第三支付公司的支付系統(tǒng),同一家銀行的可能會對接很多支付通道,比對銀聯(lián)無跳轉(zhuǎn)支付,網(wǎng)聯(lián)支付,也有可能是 XX 行自己提供的接口。

          那么這種情況就非常需要單獨(dú)維護(hù)一個路由系統(tǒng)。

          PS:630 政策之前,支付公司對接支付通道那真是一個多,同一家銀行,可能會對接四五個通道。

          但是 630政策之后, 不允許支付機(jī)構(gòu)直接對接銀行。

          所以現(xiàn)在支付機(jī)構(gòu)對接通道可能會比之前少很多。

          實(shí)現(xiàn)方式

          路由系統(tǒng)實(shí)現(xiàn)方式有很多,下面主要分享一下我所經(jīng)歷過實(shí)現(xiàn)方案。

          我們的路由系統(tǒng)經(jīng)歷過三個階段的迭代,才有了現(xiàn)在的實(shí)現(xiàn)方案。

          第一個階段-混沌初開

          這個階段就跟上面講的場景一樣,業(yè)務(wù)需求較簡單,僅僅只需要對接一兩個支付通道。

          為了快速上線,設(shè)計方案就簡單粗暴,所有業(yè)務(wù)都處于一個應(yīng)用。

          支付子模塊對內(nèi)暴露暴露支付服務(wù)接口,由業(yè)務(wù)系統(tǒng)發(fā)起直接調(diào)用。

          系統(tǒng)設(shè)計圖如下:

          這個階段由于只有一個支付渠道,所以也不需要有路由系統(tǒng),直接由業(yè)務(wù)系統(tǒng)調(diào)用支付服務(wù)接口發(fā)起支付。

          不過隨著業(yè)務(wù)量增大之后,這個設(shè)計方案就暴露很多問題:

          1. 業(yè)務(wù)系統(tǒng)與支付系統(tǒng)位于同一個系統(tǒng),系統(tǒng)任何一次變更都會影響整個系統(tǒng)。
          2. 擴(kuò)展性問題。每接入一個新的支付通道如微信,就需要增加一個新的實(shí)現(xiàn)類。另外,業(yè)務(wù)系統(tǒng)的代碼同時也需要改動,需要調(diào)用新的實(shí)現(xiàn)類。

          針對以上問題,我們進(jìn)行第一版的改造。

          首先我們將整個支付模塊從原來應(yīng)用中拆分出來,成為一個獨(dú)立的子系統(tǒng),專門運(yùn)行支付業(yè)務(wù)。

          這個系統(tǒng)對外提供一組支付接口,業(yè)務(wù)系統(tǒng)只需要調(diào)用這個接口,傳入必要的參數(shù),無需關(guān)心支付系統(tǒng)到底是如何實(shí)現(xiàn)的。

          如果業(yè)務(wù)系統(tǒng)想指定某個支付通道,比如支付寶,那么可以在接口傳入這個渠道標(biāo)識,支付系統(tǒng)將會根據(jù)這個渠道標(biāo)識調(diào)用相應(yīng)的支付通道。

          其次梳理渠道接口文檔,抽象出共性接口,每個支付通道實(shí)現(xiàn)都需要繼承這個接口。

          這組通用渠道接口,其中 「channelName」 方法,代表這個實(shí)現(xiàn)類具體代表哪個通道。比如說這個方法返回 「aliPay」,那么就代表這個實(shí)現(xiàn)類將會調(diào)用支付寶通道。

          支付系統(tǒng)子應(yīng)用中將會維護(hù)一個類似路由表,這里簡單使用 Map 存儲映射關(guān)系,「key」 為上文提到的渠道唯一應(yīng)用標(biāo)識,而 「value」 為具體的實(shí)現(xiàn)類。

          應(yīng)用初始化之后,將會調(diào)用 「Spring ApplicationContext getBeansOfType」 方法,獲取同一個接口的所有實(shí)現(xiàn)類 ,最后將其放入 Map 緩存中。

          每次支付調(diào)用都會根據(jù)渠道唯一標(biāo)識從路由表獲取具體實(shí)現(xiàn)類,然后由具體的子類實(shí)現(xiàn)支付邏輯。

          學(xué)過設(shè)計模式的同學(xué),這里應(yīng)該不會陌生,這其實(shí)是使用設(shè)計模式中的策略模式。

          這個階段,由于業(yè)務(wù)還不是很復(fù)雜,系統(tǒng)還是挺簡單,路由系統(tǒng)還只是系統(tǒng)中的一個子模塊。

          第二個階段-神功初成

          經(jīng)歷過一段時間,公司的業(yè)務(wù)量變的越來越大,這個階段我們開始追求系統(tǒng)的穩(wěn)定性。

          但是在第一階段設(shè)計方案中,支付系統(tǒng)所有模塊位于同一工程。有些模塊可能需要頻繁發(fā)布,這樣一旦發(fā)布就會影響所有系統(tǒng)功能。

          第二點(diǎn),系統(tǒng)功能全都耦合在一起,團(tuán)隊(duì)開發(fā)也變的困難,分支沖突,代碼丟失也是經(jīng)常的事。

          第三點(diǎn),一旦某些改動發(fā)布發(fā)生問題,整個系統(tǒng)都受到影響,真的是「要死一起死」。

          所以這個階段針對以上的問題,我們進(jìn)行了相應(yīng)改造,開始將支付系統(tǒng)進(jìn)行拆分。

          首先按照功能,將支付系統(tǒng)拆分幾個獨(dú)立的子系統(tǒng),路由系統(tǒng),渠道系統(tǒng),成為獨(dú)立系統(tǒng),獨(dú)立部署維護(hù)。

          每個支付通道單獨(dú)維護(hù)部署,成為一個單獨(dú)的子應(yīng)用。

          系統(tǒng)之間的調(diào)用關(guān)系,就從同一進(jìn)程內(nèi)調(diào)用,變成使用 「RPC」 進(jìn)行跨進(jìn)程調(diào)用。

          這個時候就會有個問題,渠道系統(tǒng)可能會因?yàn)榘l(fā)布而下線/上線,這時路由系統(tǒng)必須動態(tài)維護(hù)這種關(guān)系,在渠道系統(tǒng)某一節(jié)點(diǎn)下線時,自動刪除調(diào)用關(guān)系,而當(dāng)應(yīng)用上線時,新增調(diào)用關(guān)系。

          「說白了,路由系統(tǒng)需要實(shí)現(xiàn)渠道服務(wù)動態(tài)發(fā)現(xiàn)?!?/strong>

          看到這里不要怕,其實(shí) Dubbo 框架已經(jīng)自帶這個功能,我們沒必要自己再去實(shí)現(xiàn)了。

          Dubbo 配置中有一個屬性-「group」,這個屬性可以用于服務(wù)分組。

          當(dāng)同一個接口有多個實(shí)現(xiàn),我們就可以根據(jù)這個來區(qū)分不同渠道系統(tǒng)的實(shí)現(xiàn)。

          因?yàn)榍老到y(tǒng)實(shí)現(xiàn)同一組接口之后,提供出 Dubbo 服務(wù)需要加上相應(yīng)的 group 屬性,值為相應(yīng)的渠道唯一標(biāo)識。

          如下所示:

          路由系統(tǒng)只要引入這個 Dubbo 服務(wù),設(shè)置相應(yīng)的 「group」 屬性 ,路由系統(tǒng)引用渠道系統(tǒng)的服務(wù):

          此時路由系統(tǒng)就跟第一階段一樣,內(nèi)部維護(hù)一個路由表就好了。

          這里采用了 XML 配置存儲渠道標(biāo)識與 Dubbo 引用服務(wù)的映射關(guān)系,如下所示:

          服務(wù)啟動之后解析這個 XML 文件,然后將其維護(hù)在 Map 中。每次支付調(diào)用都會根據(jù)渠道唯一標(biāo)識從路由表獲取服務(wù)名,然后借助 「Spring ApplicationContext#getBean」 獲取具體的 Dubbo 引用服務(wù)。

          后續(xù)如果再新增渠道系統(tǒng),路由系統(tǒng)不需要再修改任何代碼,只要在配置文件中新增 Dubbo 服務(wù)引用以及增加路由表引用關(guān)系即可。

          第三階段-登峰造極

          第二個階段路由系統(tǒng)基本上已經(jīng)滿足現(xiàn)有階段業(yè)務(wù)實(shí)用,不過還是存在個問題,渠道應(yīng)用新增時,還需要新增配置「重啟應(yīng)用」

          之前有一次新增渠道,忘記了在路由系統(tǒng)新增配置,從而導(dǎo)致新的渠道應(yīng)用無法被調(diào)用,找了很久的問題,才發(fā)現(xiàn)是這個問題。

          所以第三階段,主要是優(yōu)化路由系統(tǒng),去掉上述配置文件,到達(dá)新增渠道應(yīng)用,而不用重啟路由系統(tǒng)。

          這個階段的改造,我們不再使用 XML 配置引用服務(wù),而是借助 「Dubbo API」 ,動態(tài)引用 Dubbo 服務(wù)。

          查看 ?Dubbo 文檔 ,可以直接使用 ReferenceConfig 直接查找服務(wù)提供者。

          官方文檔建議:

          ReferenceConfig 實(shí)例很重,封裝了與注冊中心的連接以及與提供者的連接,需要緩存。否則重復(fù)生成 ReferenceConfig 可能造成性能問題并且會有內(nèi)存和連接泄漏。在 API 方式編程時,容易忽略此問題。

          這里使用ReferenceConfigCache,用于緩存 「ReferenceConfig」 實(shí)例。

          改造之后,去除之前所有引用服務(wù)配置文件以及緩存注冊代碼,不用再使用 Map 存儲路由的映射關(guān)系。改造如下:

          總結(jié)

          回顧上文,可以看到初期沒有路由系統(tǒng),整個系統(tǒng)可以運(yùn)行下去。

          但是隨著業(yè)務(wù)量不斷變大變復(fù)雜,最開始的系統(tǒng)架構(gòu)已經(jīng)不能適應(yīng)當(dāng)前的環(huán)境,所以我們才開始系統(tǒng)拆分,進(jìn)行微服務(wù)改造,一步步改進(jìn)系統(tǒng)。

          改進(jìn)的過程中,不斷發(fā)現(xiàn)方案不足處,然后一步步迭代演進(jìn)。這個過程中,要善于利用現(xiàn)有框架的功能,加速功能的開發(fā)。

          最后,本文給出了幾種不同階段路由系統(tǒng)實(shí)現(xiàn)方式,適合不同階段、不同類型的系統(tǒng)。

          如果各位同學(xué)剛好也有類似需要,可以根據(jù)自己系統(tǒng)的情況借鑒參考。

          好了,下周見~

          后臺回復(fù)?學(xué)習(xí)資料?領(lǐng)取學(xué)習(xí)視頻


          如有收獲,點(diǎn)個在看,誠摯感謝

          瀏覽 43
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  大香蕉在线观看一区免费 | 九九东京热 | 中日韩一区二区三区久 | 黄片www. | 91久久久久久久 |