1. 程式人生 > >支付閘道器的設計

支付閘道器的設計

在支付系統中,支付閘道器和支付渠道的對接是最核心的功能。其中支付閘道器是對外提供服務的介面,所有需要渠道支援的資金操作都需要通過閘道器分發到對應的渠道模組上。一旦定型,後續就很少,也很難調整。而支付渠道模組是接收閘道器的請求,呼叫渠道介面執行真正的資金操作。每個渠道的介面,傳輸方式都不盡相同,所以在這裡,支付閘道器相對於支付渠道模組的作用,類似設計模式中的wrapper,封裝各個渠道的差異,對閘道器呈現統一的介面。而閘道器的功能是為業務提供通用介面,一些和渠道互動的公共操作,也會放置到閘道器中。

功能概述

支付系統對其他系統,特別是交易系統,提供的支付服務包括簽約,支付,退款,充值,轉帳,解約等。有些地方還會額外提供簽約並支付的介面,用於支援在支付過程中綁卡。 每個服務實現的流程也是基本類似,包括下單,取消訂單,退單,查單等操作。每個操作實現,都包括引數校驗,支付路由,生成訂單,風險評估,呼叫渠道服務,更新訂單和傳送訊息這7步,對於一些比較複雜的渠道服務,還會涉及到非同步同通知處理的步驟。這裡詳細介紹這些步驟的實現要點。

1. 執行引數校驗

所有的支付操作,都需要對輸入執行引數校驗,避免介面受到攻擊。

  • 驗證輸入引數中各欄位的有效性驗證,比如使用者ID,商戶ID,價格,返回地址等引數。

  • 驗證賬戶狀態。交易主體、交易對手等賬戶的狀態是處於可交易的狀態。

  • 驗證訂單:如果涉及到預單,還需要驗證訂單號的有效性,訂單狀態是未支付。為了避免使用者快取某個URL地址,還需要校驗下單時間和支付時間是否超過預定的間隔。

  • 驗證簽名。簽名也是為了防止支付介面被偽造。 一般簽名是使用分發給商戶的key來對輸入引數拼接成的字串做MD5 Hash或者RSA加密,然後作為一個引數隨其他引數一起提交到伺服器端。

2. 根據支付路由尋找合適的支付服務

根據使用者選擇的支付方式確定用來完成該操作的合適的支付渠道。使用者指定的支付方式不一定是最終的執行支付的渠道。比如使用者選擇通過工行信用卡來執行支付,但是我們沒有實現和工行的對接,而是可以通過第三方支付,比如支付寶、微信支付、易寶支付,或者銀聯來完成。那如何選擇合適的支付渠道,就通過支付路由來實現。支付路由會綜合考慮收費、渠道的可用性等因素來選擇最優方案。

3. 評估交易風險

檢查本次交易是否有風險。風控介面返回三種結果:阻斷交易、增強驗證和放行交易。

  1. 阻斷交易,說明該交易是高風險的,需要終止,不執行第5個步驟;

  2. 增強驗證,說明該交易有一定的風險,需要確認下是不是使用者本人在操作。這可以通過傳送簡訊驗證碼或者其他可以驗證使用者身份的方式來做校驗,驗證通過後,可以繼續執行該交易。

  3. 放行交易,即本次交易是安全的,可以繼續往下走。

4.生成交易訂單

將訂單資訊持久化到資料庫中。當訪問壓力大的時候,資料庫寫入會成為一個瓶頸。

5. 呼叫支付渠道提供的服務

所有的支付服務都需要第三方通道來完成執行。一般銀行渠道的呼叫比較簡單,可以直接返回結果。一些第三方支付,支付寶,微信支付等,會通過非同步介面來告知支付結果。

6. 更新訂單

對於同步返回的結果,需要在主執行緒中更新訂單的狀態,標記是支付成功還是失敗。對於非同步返回的渠道,需要在非同步程式中處理。

7. 傳送訊息

通過訊息來通知相關係統關於訂單的變更。風控,信用BI等,都需要依賴這資料做準實時計算。

8. 非同步通知

如上述流程,其中涉及到呼叫遠端介面,其延遲不可控。如果呼叫方一直阻塞等待,很容易超時。引入非同步通知機制,可以讓呼叫方在主執行緒中儘快返回,通過非同步執行緒來得到支付結果。對於通過非同步來獲取支付結果的渠道介面,也需要對應的在非同步通知中將結果返回給呼叫方。 非同步通知需要呼叫方提供一個回撥地址,一般以http或者https的方式。這就有技術風險,如果呼叫失敗,還需要重試。而重試不能過於頻繁,需要逐步拉大每一次重試的時間間隔。 在非同步處理程式中,訂單根據處理結果變更狀態後,也要發訊息通知相關係統。

整體架構

整體軟體參考架構如下所示:


支付閘道器前置

支付閘道器前置是對接業務系統,為其提供支付服務的模組。它是所有支付服務介面的整合前置,將不同支付渠道提供的介面通過統一的方式呈現給業務方。這樣接入方就只需要對接支付閘道器,增加和調整支付渠道對業務方是透明的。 支付閘道器前置的設計對整個支付系統的穩定性、功能、效能以及其他非功能性需求有著直接的影響。

在支付閘道器中需要完成大量的操作,為了保證效能,這些操作都儘量非同步化來處理。

支付閘道器前置應保持穩定,儘量減少系統重啟等操作對業務方的影響。支付閘道器也避免不了升級和重啟。這可通過基於Nginx的LBS(Load Balance System)閘道器來解決。LBS在這裡有兩個作用: 一個是實現負載均衡,一個是隔離支付閘道器重啟對呼叫的影響。 支付閘道器也採用多臺機器分散式部署,重啟時,每個伺服器逐個啟動。某臺伺服器重啟時,首先從LBS系統中取消註冊,重啟完成後,再重新註冊到LBS上。這個過程對呼叫方是無感知的。

為了避免介面受攻擊,在安全上,還得要求業務方通過HTTPS來訪問介面,並提供防篡改機制。防篡改則通過介面引數簽名來處理。現在主流的簽名是對介面引數按照引數名稱排序後,做加密和雜湊,參考微信的簽名規範

交易流水和記賬

每一筆交易都需要記錄流水,並登記到個人和機構的分戶賬戶上,統計和分析也需要根據交易流水來更新相關資料。 而個人和機構賬戶總額更新、交易流水記錄以及庫存的處理,更是需要事務處理機制的支援。 從效能角度, 可以弱化了事務處理的要求,採用訊息機制來非同步化和交易相關的資料處理。

  1. 在支付閘道器前置的主流程中,僅記錄交易流水,即將當前的請求儲存到資料庫中。

  2. 完成資料記錄後,傳送MQ出來,記賬、統計、分析,都是接收MQ來完成資料處理。

  3. 涉及到本地資金支付,比如錢包支付,會需要分散式事務處理,扣減賬號餘額,記賬,扣減庫存等,每個操作失敗,都要回滾。阿里有很不錯的分享,這裡不詳細描述。

  4. 當交易量上來後,需要考慮交易表的分表分庫的事情。分表分庫有兩個策略,按照流水號或者交易主體id來走。後者可以支援按使用者來獲取交易記錄。我們用的是前者。後者可以走elastic,確保資料庫專用。風控,信用和統計所需要的資料,通過MQ同步到Hbase裡面。作為支付系統最有價值的資料,在儲存上做到專庫專用,無可厚非,畢竟儲存成本還是廉價的。


風控模組

風控對支付的重要性怎麼強調都不過分。有些系統在風控出問題時可以旁路風控,但是在支付系統中,風控出問題必須停止交易。 整體上,風控可以分為資料採集,資料分析,實時計算,規則配置,實時攔截等模組。風控本身是個大話題,以後專門討論。又欠一個債。 但風控和交易的介面比較簡單。對每一次交易,風控一般返回三個結果:攔截,增強驗證,通過。通過指交易沒有問題,可以直接放行。攔截則是阻止本次交易。增強驗證則是交易存疑,需要使用者進一步核實身份才能繼續,比如輸入手機號或者身份證號,一般用於身份被盜用的場景。而人工核實則是對交易有疑問,一般用於個人惡意消費滿場景。


支付路由

支付路由是一個複雜的話題。對支付系統來說,能支援的支付方式越多越好,不能由於支付方式的不支援斷了財路。現實中的支付方式多得難以置信。使用者隨時甩出一張你聽都沒聽說過的卡。如果一個銀行卡只有幾個使用者在用,那針對這個卡開發個對接有點得不嘗失。現在第三方支付的爆發,確實給開發支付系統省了不少事。但是公司不可能只對接一個第三方支付,如果這個渠道出問題了,或者鬧矛盾了,把連結給掐了,老闆還不欲哭無淚。總之,得對接多個渠道。對於交易量大的銀行,還得考慮直聯。

支付路由的作用是定義對使用者選用的銀行卡或者其他支付方式,使用什麼渠道來完成支付。

一般來說,銀行會提供兩種支付途徑:無跳轉的快捷支付介面和帶跳轉的網銀介面。前者在綁卡,支付的時候,不需要跳到銀行頁面上去處理,後者則需要在銀行的網銀頁面上完成。顯然前者對使用者來說體驗要好多了,使用者流程不會被打斷。快捷支付要求支付系統在本地儲存使用者的支付資訊,如卡號,登記手機。系統要確保這些資訊不被洩漏。風險非常好,所以大部分銀行要求接入方必須經過ADSS檢驗才能夠接入快捷支付。

這種固定方式的接入有單點故障的問題,一旦某個渠道出問題,繫結的支付方式就無法使用。改進策略是為每個支付方式定義多個渠道,第一個渠道出問題即選擇第二個,以此類推。

當然,更進一步,可以為候選渠道定義權重,按照權重來選擇支付方式。當渠道出問題,自動調整權重。

路由實現上還會更復雜,對同一張銀行卡,運營上會要求在不同的系統上,比如android,iOS,windows上,或者不同地區,如大陸,臺灣,香港,北美等,甚至不同業務上,採用不同渠道來支付。

支付渠道

如果採用微服務來實現,整體設計上,可以考慮將支付渠道分離、支付閘道器前置分離。支付渠道的微服務實現有兩種策略,一種是按照服務來拆分,一種是按照渠道來拆分。

  • 按渠道拆分,指每個渠道單獨部署在一個容器中,對支付閘道器提供相同的服務。

  • 按服務拆分,是按介面來拆分,分為支付,對賬,退款等子系統,每個服務單獨部署,所有容器的服務都實現在一起。

渠道拆分

按照服務來拆分的一個典型案例是大眾點評網的早期實現。 大眾點評支付渠道網關係統的實踐之路。 每個支付服務介面實現為一個獨立的子系統,獨立部署,通過支付閘道器前置來對外提供服務。 這篇文章裡面也提到這種方式存在的問題,

  • 銀行的加密客戶端會有各種奇葩的需求,有些可以支援linux,有些要windows系統,如何在一個容器中滿足所有需求?

  • 這樣拆分後,每個渠道介面獨立部署。某個渠道出問題也不會影響其他渠道。至於渠道訪問量小導致資源浪費問題,可以通過虛機或者docker的資源排程來解決,誰也不會在物理機上玩微服務。

  • 對接渠道難點在於對輸入輸出做加密和解密,以及組裝和解析報文。同一個渠道對不同的服務的加密解密方式是一樣的,報文格式也是一樣的。按渠道來構建服務可以共用這樣方法,減少開發投入。

  • 從安全的角度,按渠道劃分也有優勢。一般渠道都要求只對接到特定ip的機器,這樣每個渠道對接系統所在的機器僅開放對渠道和支付閘道器前置機的訪問白名單即可,儘可能的縮減被暴露的風險。

接入渠道

對於支付渠道,首先考慮的是接入哪些渠道。要對接的渠道按優先順序有:

  • 第三方支付,對大部分應用來說,支付寶和微信支付都是必須的,一般來說,這兩者可以佔到90%以上的交易量。使用者不需要綁卡,授權後直接支付就行。各種平臺都支援,效能和穩定性都不錯。對於一些特殊業務,比如遊戲,企業支付,可以檢視一些專用的第三方支付平臺。

  • 銀聯,這貨的存在,極大方便了和銀行的對接。和第三方支付主要不同在兩個地方一是需要綁卡,也就是使用者先把卡號,手機,身份證號提供出來。這一步會折損不少使用者。綁卡後,以後的支付操作就簡單了,使用者只需要輸入密碼就行。手機客戶端不需要像第三方支付那樣安裝SDK,都在伺服器端完成。當然,這是針對快捷支付。網銀支付還是挺麻煩的。銀聯接入也需要ADSS認證。

  • 銀行,建議先看這一篇文章,瞭解下對接銀行的難度。那最終需要選擇哪些銀行?先看個統計資料。 截至 2015 年底,我國銀行業金融機構包括 5 家大型商業銀行、12 家股份制商業銀行、133 家城市商業銀行、5 家民營銀行、859 家農村商業銀行、71 家農村合作銀行、1373家農村信用社、1 家郵政儲蓄銀行、3 家政策性銀行、 311 家村鎮銀行、48 家農村資金互助社。優先選擇5家商業銀行,他們佔40%的交易量。其次是股份制銀行和郵儲。這就18家銀行了。老闆要是不滿意,城商行和農商行加起來有1000多家呢。一般對接一個銀行預計有3周左右的工作量,大部分銀行需要專線接入,費用和頻寬有關,一年也得幾萬費用。不同銀行對接入環境有不同要求,這也是成本。另外,還有一個重大風險,就是央行在搞得網聯絡統,畢竟還沒有出來,相關資料參考知乎上關於網聯的一篇討論

  • 手機支付,現在不少廠商都內建了各種支付,比如蘋果的In-App支付, 三星支付、華為支付等, 這些支付僅針對特定的手機型號, 支援NFC等,根據業務需要也可以接入。 就是目前使用者群不大,收益不明顯。

  • 話費支付, 這一塊容易被人忽略,但考慮到國內不少職場人士,話費是公司報銷的,每個月多的用不完,所以這塊支付還是相當有市場的。 問題是,聯通和移動兩大運營商,不僅介面不能互通,內部各個地域也是各自為政,所以對接起來還是有點麻煩。不過話費支付領域也有類似支付寶微信的第三方支付公司,比如虹軟、聯動優勢等公司。

這篇文章對支付系統整體設計做一個概要描述,其實每個模組都是一個大坑,有很多的技術細節。 歡迎大家提提意見,一起探討。

轉載地址:https://mp.weixin.qq.com/s/ljzLwWQMkKX2olVTOTvu3w