資金服務(wù)架構(gòu)設(shè)計(jì)

背景介紹

作為互金公司來(lái)說(shuō),需要從銀行、信托等三方機(jī)構(gòu)獲取資金,來(lái)支持其分期、貸款等消金業(yè)務(wù)。為了能快速接入資方,滿足業(yè)務(wù)對(duì)資金的需求,我們抽象了資金服務(wù),資金服務(wù)作為對(duì)接外部廠商的端口,要協(xié)調(diào)業(yè)務(wù)與資方的各種差異,將不同機(jī)構(gòu)提供的接口通過(guò)統(tǒng)一的方式呈現(xiàn)給業(yè)務(wù)方,是業(yè)務(wù)系統(tǒng)的重要支撐。且由于對(duì)接的各銀行和第三方系統(tǒng)的穩(wěn)定性參差不齊,通道故障時(shí)有發(fā)生,作為承接上下游的核心系統(tǒng),要在一系列不穩(wěn)定的系統(tǒng)之上建立一個(gè)可以給上游提供穩(wěn)定服務(wù)的系統(tǒng)。

架構(gòu)設(shè)計(jì)

資金服務(wù)架構(gòu)

資方服務(wù)拆分為資金服務(wù)、代理服務(wù)、以及資方路由服務(wù)。資金服務(wù)進(jìn)行參數(shù)組裝和流程串聯(lián),資金代理負(fù)責(zé)和外部資方機(jī)構(gòu)進(jìn)行網(wǎng)絡(luò)通信,資方路由服務(wù)提供規(guī)則配置,及給用戶推薦合適的資金方。

請(qǐng)求流程

請(qǐng)求流程時(shí)序圖

流程
  • 請(qǐng)求單冪等,并落庫(kù)
    每個(gè)請(qǐng)求會(huì)攜帶一個(gè)requestId(客戶端通過(guò)分布式id生成器生成),服務(wù)收到請(qǐng)求后,會(huì)拿著此requestId從請(qǐng)求流水表(requestId為流水表的主鍵,流水表會(huì)記錄請(qǐng)求的入?yún)?,及最終的返回結(jié)果,還有異常信息)中查詢記錄,如果已經(jīng)存在,則直接返回流水表記錄的結(jié)果信息。如果不存在直接插入,并捕獲重復(fù)主鍵異常,確保并發(fā)下的冪等,然后,插入一條記錄到task表(在同一個(gè)事務(wù)中),關(guān)聯(lián)id為requestId,并記錄任務(wù)類型,然后直接返回"進(jìn)行中"(中間狀態(tài))。
  • 任務(wù)推送
    定時(shí)任務(wù)掃描task表,服務(wù)請(qǐng)求資方接口,得到同步結(jié)果,并更新請(qǐng)求流水表的狀態(tài),刪除task表,將task記錄移到history_task中(同一事務(wù))。若發(fā)生異常,則增加task表的retry次數(shù)字段,等待下次重推,查看該接口的配置中是否支持冪等,若支持冪等,則重推,否則調(diào)用資方的結(jié)果查詢接口,若未在資方系統(tǒng)落單,則重試,否則直接將流水表置位終態(tài)。成功后會(huì)進(jìn)行相關(guān)單據(jù)的創(chuàng)建和更新。當(dāng)異常后,三次重推失敗后,會(huì)停止重推,觸發(fā)報(bào)警機(jī)制,人工介入。
  • 結(jié)果消息推送
    當(dāng)資金服務(wù)獲取得到最終結(jié)果后,會(huì)通過(guò)kafka將結(jié)果異步推送到到業(yè)務(wù)系統(tǒng)。也提供了結(jié)果查詢接口,讓業(yè)務(wù)系統(tǒng)定時(shí)調(diào)用,防止結(jié)果消息丟失。

資金路由流程

路由流程

解決的問(wèn)題

  • 屏蔽不同資方接口的參數(shù)及流程差異
    我們?cè)诔槌鲑Y金服務(wù)之前,不同的資方的流程和接口參數(shù)耦合到了業(yè)務(wù)系統(tǒng)之中,使得每次新接入資方,業(yè)務(wù)系統(tǒng)的流程就要進(jìn)行重構(gòu),效率很低及不穩(wěn)定。
    解決方案:通用接口 + 統(tǒng)一入?yún)?+ 參數(shù)聚合
    我們抽象了通用的接口,和通用的流程,業(yè)務(wù)系統(tǒng)只需按照固定的流程調(diào)用我們的接口即可,且參數(shù)只需要傳輸通用的必須的參數(shù),如訂單號(hào),資方編碼等,由資金服務(wù)通過(guò)數(shù)據(jù)服務(wù)根據(jù)資方接口的要求獲取所需的數(shù)據(jù)并進(jìn)行參數(shù)的拼接,和對(duì)資方的接口進(jìn)行組合。


    屏蔽流程差異
  • 接口的響應(yīng)時(shí)間依賴于外部資方接口,資方接口的響應(yīng)時(shí)間不可控,導(dǎo)致超時(shí)。這時(shí)候可能出現(xiàn)業(yè)務(wù)方調(diào)用失敗,但是資方成功的數(shù)據(jù)不一致的情況。且同步接口失敗在系統(tǒng)內(nèi)不好進(jìn)行重試
    解決方案:預(yù)落單 + 異步 + 任務(wù)推送。異常都資金服務(wù)自行進(jìn)行重試及處理,不會(huì)因任何交互異常而影響上游獲取結(jié)果的準(zhǔn)確性,能讓上游感知的,都是明確的、資金服務(wù)不能處理的異常。


    請(qǐng)求異步化
  • 部分資方的接口超時(shí),占用線程,導(dǎo)致其他資方的請(qǐng)求阻塞
    解決方案:線程池隔離,不同資方的不同接口的異步請(qǐng)求線程池相互獨(dú)立,防止相互影響。其實(shí)當(dāng)不同接口的請(qǐng)求量不同,即不同的業(yè)務(wù)模塊相互影響時(shí),也可以采用業(yè)務(wù)隔離的方式,例如授信部署在一個(gè)節(jié)點(diǎn),用信部署在另外的節(jié)點(diǎn)。

  • 線程池的監(jiān)控與動(dòng)態(tài)配置

  • 對(duì)系統(tǒng)中不穩(wěn)定的因素進(jìn)行熔斷降級(jí)
    1)使用sentinel對(duì)資方的接口進(jìn)行保護(hù),當(dāng)異常數(shù)和響應(yīng)時(shí)間(不同接口的設(shè)置響應(yīng)時(shí)間也不同,有的1s就異常,有的會(huì)3s)超過(guò)閾值時(shí),這個(gè)資源的調(diào)用進(jìn)行限制,讓請(qǐng)求快速失敗,避免影響到其它的資源而導(dǎo)致級(jí)聯(lián)錯(cuò)誤。當(dāng)資源被降級(jí)后,在接下來(lái)的降級(jí)時(shí)間窗口(10分鐘)之內(nèi),對(duì)該資源的調(diào)用都自動(dòng)熔斷(默認(rèn)行為是拋出 DegradeException)。
    2)降級(jí)策略:異常屬性上報(bào),進(jìn)行報(bào)警;失敗的請(qǐng)求task記錄狀態(tài)置為降級(jí)狀態(tài);會(huì)被并將該資方接口置為不可用狀態(tài),作為資方路由路由功能的前置判斷依據(jù)。

  • 對(duì)外提供的業(yè)務(wù)接口也接入sentinel進(jìn)行限流
    1)根據(jù)請(qǐng)求的qps和并發(fā)線程數(shù)進(jìn)行流控

代碼結(jié)構(gòu)設(shè)計(jì)

  • 模板策略:經(jīng)典設(shè)計(jì)模式的合理利用
  • 面向接口:以Node接口為基礎(chǔ),可以按需繼承AsyncQuery、CallBack、TaskExecutor等單一職責(zé)接口
    代碼聚合:Node接口通過(guò)繼承其他接口,把一個(gè)節(jié)點(diǎn)的主要流程封裝進(jìn)一個(gè)Node,可讀性高,入手easy
    聲明式身份:用FundCode、NodeCode接口為Node實(shí)例聲明身份,避免修改beanId
    多方向調(diào)度:統(tǒng)一的Task模板聚合TaskExecutorMap進(jìn)行調(diào)度;統(tǒng)一的回調(diào)入口聚合CallBackMap進(jìn)行調(diào)度。


    image.png

    通過(guò)fundCode(資方編碼)+ nodeCode(功能編碼)可以唯一確定一個(gè)nodeService,所以我們新接入資方的時(shí)候就可以新增nodeService實(shí)現(xiàn)即可,不會(huì)對(duì)原來(lái)資方的功能代碼產(chǎn)生影響。且nodeService還可以按需實(shí)現(xiàn)callback,taskExecutor、asyncQuery等接口實(shí)現(xiàn)回調(diào)、定時(shí)任務(wù)、異步查詢等能力。

表設(shè)計(jì)

  • 請(qǐng)求流水表
  • 授信單:存儲(chǔ)授信記錄,每個(gè)月300多萬(wàn)單數(shù)據(jù)增長(zhǎng),當(dāng)授信記錄達(dá)到6千萬(wàn)的時(shí)候,對(duì)授信單進(jìn)行了分表,在老庫(kù)中分成8張表,分表id為用戶id,采用基因分表法,授信單號(hào)(時(shí)間戳+機(jī)器碼+分表id+隨機(jī)數(shù))。
  • 放款單:存儲(chǔ)放款記錄
  • 還款單:存儲(chǔ)相關(guān)的還款記錄
  • 代償記錄
  • 任務(wù)表/歷史任務(wù)表
  • 賬戶表
  • 賬戶的動(dòng)賬流水表
  • 影像文件表


    image.png

聯(lián)調(diào)問(wèn)題

  • 業(yè)務(wù)方聯(lián)調(diào)時(shí),資方系統(tǒng)未達(dá)到聯(lián)調(diào)要求,如何不影響聯(lián)調(diào)進(jìn)度?
    解決方案:增加AOP處理,攔截特定的請(qǐng)求進(jìn)行Mock,工程配置mock.json文件,啟動(dòng)解析mock配置,運(yùn)行時(shí)通過(guò)參數(shù)匹配來(lái)判斷是否執(zhí)行mock。
    mock.json整體是一個(gè)map,第一層是類名,第二層是方法名,然后就是jsonobj數(shù)組,每一個(gè) jsonobj就是一個(gè)匹配,數(shù)組里的jsonobj。主要有一下幾個(gè)字段
    matchKey:用于匹配特定的字段
    matchValue:如果matchKey不為空則判斷指定的成員變量是否為此值,如果matchKey為空則忽略判斷參數(shù)里是否有此值。
    syncResult:同步返回值,jsonObj
    asyncResult:異步返回值,jsonStr
{
  "com.xxx.xxx.xxxService": {
    "creditApply": [
      {
        "matchKey": "mobile",
        "matchValue": "1398888xxxx",
        "syncResult": {
          "code": "0",
          "msg": "success",
          "requestNo": "110"
        },
        "asyncResult": "ok"
      }
    ]
  }
}
  • 與第三方接口的聯(lián)調(diào)工作要與開發(fā)并行。開發(fā)人員經(jīng)常會(huì)天然的把“技術(shù)含量最高”的開發(fā)工作作為最優(yōu)先的部分,迫不及待的投入到編碼中,等到開發(fā)完成或者完成的差不多了,才開始進(jìn)行聯(lián)調(diào)這是不對(duì)。因?yàn)橄到y(tǒng)之間的風(fēng)險(xiǎn)天然的是大于系統(tǒng)內(nèi)部的風(fēng)險(xiǎn)的。因?yàn)橛幸韵聨追N情況:
    1) 對(duì)方提供了技術(shù)文檔,但是有錯(cuò)或者版本太舊,誤導(dǎo)了你,最后測(cè)試才發(fā)現(xiàn);
    2) 對(duì)方技術(shù)文檔沒問(wèn)題,但是你的業(yè)務(wù)需求,恰好觸發(fā)了對(duì)方系統(tǒng)的某個(gè)問(wèn)題,對(duì)方需要很久才能解決;
    3)對(duì)方公司對(duì)你這個(gè)項(xiàng)目的優(yōu)先級(jí)設(shè)得很低的,指派的對(duì)接人員很不好說(shuō)話甚至是個(gè) sb,完全不顧你的死活。
    解決這個(gè)問(wèn)題的方法很簡(jiǎn)單,就是“盡量早,盡量深入的和對(duì)方進(jìn)行溝通”。通過(guò)溝通,盡早識(shí)別對(duì)方的人員水平和態(tài)度,識(shí)別對(duì)方的文檔和產(chǎn)品質(zhì)量,有針對(duì)性的及早采取對(duì)策,風(fēng)險(xiǎn)前置。

早期進(jìn)行 demo 聯(lián)調(diào),不但可以盡早驗(yàn)證對(duì)方的產(chǎn)品,還可以盡早建立和對(duì)方人員的聯(lián)系,判斷對(duì)方人員的水平和態(tài)度。

其他技術(shù)點(diǎn)

  • 分布式鎖 (setnx復(fù)合命令+lua腳本實(shí)現(xiàn)),目前轉(zhuǎn)為redisson(可重入,可阻塞,支持鎖續(xù)期)
  • sentinel機(jī)構(gòu)超時(shí)接口的快速失敗,防止阻塞任務(wù)線程池
  • traceId鏈路追蹤
  • 拆解依賴關(guān)系,并行處理(從數(shù)據(jù)服務(wù)拼接數(shù)據(jù))
  • 使用freemarker模板引擎來(lái)進(jìn)行資方請(qǐng)求報(bào)文的參數(shù)化映射,freemarker模板文件中key對(duì)應(yīng)的具體的值采用占位符的形式,從前置的實(shí)體對(duì)象中取值,將變化點(diǎn)使用占位符表達(dá)式來(lái)解決。
  • 接入對(duì)賬平臺(tái),t+1進(jìn)行對(duì)賬,每天凌晨會(huì)對(duì)白天的交易進(jìn)行對(duì)賬,這樣可以及時(shí)發(fā)現(xiàn)不一致的數(shù)據(jù)。

接入的銀行渠道

1.工行
2.光大
3.渤海
4.新網(wǎng)
5.眾邦
6.微眾
7.中關(guān)村銀行
8.渤海
9.湖南信托
10.藍(lán)海銀行
11.民生
12.交通
13.招商

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容