支付系統通常須要對接多個支付渠道,一是爲了保證系統的可靠性,不能由於單一渠道的問題影響整個支付系統。二是爲了提升支付能力,不一樣渠道提供支付能力不一樣。三是爲了下降支付成本。html
對接多個支付渠道之後,爲了能夠正確選擇支付渠道支付,所以設計渠道路由系統。apache
從上圖能夠看到路由系統功能其實很簡單,分發支付請求到正確的渠道。但就是這個簡單系統,也通過幾回系統改造升級,最終才成爲如今的樣子。下面就來講說這個系統是如何演進。編程
下面假設對接支付渠道爲支付寶與微信。api
支付系統初期,這個階段業務需求較簡單,僅僅須要知足一個支付場景(例如使用支付寶支付)。爲了快速上線,設計方案就簡單粗暴,對外直接暴露支付服務接口,由業務系統發起直接調用。緩存
系統設計圖以下:微信
這個階段因爲只有一個支付渠道,因此也不須要有路由系統,直接由業務系統調用支付服務接口發起支付。架構
這個設計方案存在不少問題:框架
針對以上問題,將系統進行了相應改造。性能
首先是將支付系統與業務系統單獨拆分出來,成爲兩套單獨的系統。支付系統對外暴露一組通用接口。業務系統僅對接這組接口。業務系統若想指定支付渠道支付,接口參數傳入渠道標識便可。這樣就將耦合在業務系統中路由功下沉到支付系統。微信支付
其次梳理渠道接口文檔,抽象出共性接口。接入新支付渠道,只要繼承接口,實現相關方法便可,簡化渠道開發難度。
改版後的系統實現圖以下:
此時,路由系統知識支付系統的一個模塊,具體實現以下。
首先定義通用渠道接口,其中 channelName 方法,返回渠道渠道惟一標識,如支付寶渠道返回 aliPay。
而後根據 Spring ApplicationContext getBeansOfType 方法,獲取實現同一個接口的全部 Bean.最後將其放入 Map 緩存中,其中鍵值爲 channelName 方法返回渠道標識。
這個階段方案的問題在於支付系統全部模塊位於同一工程。有些模塊須要頻繁發佈,而有些模塊,如渠道模塊,路由模塊改動就不多。這樣就致使系統任一改動發佈,影響整個支付系統可用性。
針對初期後面的問題,進行了相應改造。
首先仍是進行拆分,將支付系統按照模塊拆分。路由系統,渠道系統,成爲獨立系統,獨立部署維護。
系統之間調用採用 RPC 通信,使用 Dubbo 框架。
相關實現以下:
相關接口邏輯不變,只是將同一進程內調用變成跨系統的調用。
渠道系統提供服務:
這裏改動,將渠道標識放入 Dubbo 服務 group 字段,藉助 Dubbo 分組功能標識中惟一的渠道系統。
路由系統引用渠道系統的服務:
這裏一樣須要設置 group 且須要和服務提供者一致。而後在路由系統中將服務註冊到緩存中,使用渠道標識爲 key,渠道服務名爲 value。
最後路由系統藉助 Spring ApplicationContext getBean 獲取具體的服務。
這個設計的問題在於:
路由系統中須要手動引用渠道系統服務,而後再註冊。這樣在增長渠道系統就比較繁瑣。那是否是能夠作到增長渠道系統時,無需修改路由系統,路由系統自動發現服務?
藉助 Dubbo API。
查看 Dubbo 文檔,能夠直接使用 ReferenceConfig 直接查找服務提供者。
官方文檔建議:
ReferenceConfig 實例很重,封裝了與註冊中心的鏈接以及與提供者的鏈接,須要緩存。不然重複生成 ReferenceConfig 可能形成性能問題而且會有內存和鏈接泄漏。在 API 方式編程時,容易忽略此問題。
這裏使用ReferenceConfigCache,用於緩存 ReferenceConfig 實例。
去除以前全部引用服務配置文件以及緩存註冊代碼,引入 ReferenceConfigCache,改造以下。
回顧上文路由系統,能夠看到初期沒有路由系統,整個系統能夠運行下去。可是隨着系統複雜度提升,初期系統架構已經不能知足系統的高效運行,因此才一步步改進系統。改進的過程當中,不斷髮現方案不足處,而後一步步迭代演進。這個過程當中,要善於利用現有框架的功能,加速功能的開發。