乾貨| 支付系統如何進行分散式改造
傳統支付系統面臨的挑戰
隨著近年來移動支付的興起 ,如條碼支付、聲波支付、NFC近場支付等,隨之還產生了聚合支付把多種支付方式聚合在一起,方便人們的使用,移動支付已經滲透到我們生活的每一個角落,不帶錢包出門已經沒有任何阻礙。
這就給傳統的支付系統提出了新的挑戰,用戶量激增,系統容量和性能跟不上了。傳統的架構往往以IOE技術為主,採用scale up方式以更強的硬體提升系統性能和容量,擴容成本將是巨大的。
支付機構是持牌機構,都有受到監管,對系統穩定性有強要求,傳統架構下往往都會用冷備的方式來進行容災,意味著又要投入一倍的成本。由於資料庫主備複製的延時,必須等到數據同步完成才可以切換,容災切換時間長,進行分散式改造已經刻不容緩。
分散式架構有著海量、成本、穩定、速度的優勢,其核心思想是「解決一切單點」,單點容易出故障、性能有瓶頸,那麼就拆分成多個點。垂直拆分能更清晰化模塊劃分,區分治理,水平切分能解決大數據量性能瓶頸問題,分散式改造主要是將這兩者結合起來對傳統架構進行改造。
分散式改造之垂直拆分
垂直拆分就是將原來一個整體的系統按業務模塊拆分成多個系統。系統內部數據是自包含的,不會與別的系統共用資料庫,系統與系統之間的交互通過暴露和調用服務來實現。那麼如何按照業務來拆分呢?
為了方便理解,首先我們來看一下一筆支付過程是如何進行的:
圖:簡化的支付路徑圖(註:該圖來自螞蟻金服內部)
- 商戶發起收單請求,經過API網關,調到產品層的「在線收單」產品
- 調用收銀台選擇支付方式,也可能直接進入支付環節,創建交易流水
- 進行支付處理,通過金融交換從銀行扣客戶帳,記錄帳務流水,入商戶帳,記錄賬務流水
- 對交易按照費率進行收費,記錄收費的帳務流水。此時會非同步觸發營銷和風控策略
- 日終會非同步進行會計記帳(也有同步記會計帳的)、業會核對、清結算和對帳處理
那麼從這個過程我們就可以大概推演出支付系統的一般應用架構:
圖:支付系統的應用架構
那麼如何進行垂直拆分呢?剛剛我們推演的應用架構派上用場了。
什麼是應用架構:應用架構定義一個大型軟體系統由哪些應用子系統構成,以及應用之間如何分工和合作。好的應用架構抽象合理、協作有序、易於擴展、能夠復用。有了這個應用架構,我們可以非常清晰的根據應用架構劃分的子系統來拆分。
從架構上來說,分為四層:
圖:支付系統的分層
渠道層:商戶和客戶的交易請求的入口。一般會劃分以下系統:商戶網站、用戶網站、無線接入、API網關。
產品層:通過基礎服務層提供的服務組裝成具體業務場景功能,對客戶、商戶運營等人員提供服務。一般會把服務商戶的功能劃分為商戶域,服務C端用戶的劃分為用戶域。可以按照這兩個域拆分成兩個子系統,也可以更進一步根據不同產品特性再拆分,比如商戶域中的收單產品、虛擬產品、垂直行業產品。
公共服務層:將各個產品都需要使用的些服務抽像成公共服務。一般會劃分:收銀台、交易支付、計費等系統。比如說產品層可以通過組裝各種交易類型和收費規則形成不同的產品。
基礎業務層:支付系統的核心,資金和客戶信息的處理都在這裡。一般會劃分三大子系統:帳務核心、會計核心、會員核心。
其它支撐系統:
網關:負責與銀行、銀聯等金融機構進行資金交換,與外部合作夥伴接入,如渠道拓展商、行業客戶等。一般劃分:銀行接入網關和合作夥伴接入網關。
運營支撐:貫穿於四個層的是運營支撐域:一般會劃分運營支撐、安全、風控、營銷子系統。
垂直拆分本質上是服務化改造,除了上面的講的按業務拆分,還需要一套分散式服務框架的支撐。
分散式改造之水平拆分
前面講的垂直拆分只是把系統按業務模塊劃分到不同的子系統,資料庫也分到了不同系統,但沒有解決單表大數據量的問題,而水平切分就是要把一個表按照某種規則把數據劃分到不同表或資料庫里。簡單的說就是做分庫分表。
在做分庫分表之前我們需對數據模型進行分類,分為「流水型數據」、「狀態型數據」和「配置型數據」。
- 流水型數據:像流水一樣不斷增長的數據,各條數據間是獨立的。如支付訂單、交易流水、帳務流水(入帳/出帳)、會計流水等。
- 狀態型數據:代表一個對象當前的狀態的數據。如會員信息、客戶信息、帳戶信息、會計帳。
為什麼有會員信息還有客戶信息?會員往往是註冊在支付平台的用戶,一個人可以註冊多個會員,但是一個自然人只可能有一個客戶信息,一個會員通過實名認證後就關聯上了客戶信息。無論一個客戶註冊多少個會員,實名認證後都只有一個客戶信息。
- 配置型數據:系統中用作為配置的數據。如產品、手續費率、分支機構信息、支付路由規則、會計科目等。
流水型數據會不斷產生,且各條數據間是獨立的,天然適合進行分庫分表。
狀態型數據讀寫比相當,每一次寫操作必須基於前一個正確的狀態,可以評估一下數據量的大小,數據量如果大或者要實現單元化架構,也需要進行分庫分表,提高並發處理能力,同時方便隔離故障影響。如果使用mysql資料庫,單表最好不要超過五百萬條記錄。
配置型數據,讀多寫少,強依賴讀,弱依賴寫,不要求嚴格的讀一致性,且配置型數據一般數據量不會很大,不需要進行分庫分表設計。但是業務處理中往往又需要用到,傳統架構的老系統可能使用了一些關聯表操作,關聯到了配置數據,分庫後其它數據與配置不在一個庫,不能進行關聯表操作,由於配置型數據不要求嚴格的讀一致性的特點,可以將配置型數據載入到分散式緩存里,如redis、memcached,由業務代碼來做「join」。
那麼分庫分表按照什麼規則來拆分呢?通常我們不會按實體id進行hash取模的方式來拆分。因為我們希望同一個用戶的數據能夠在同一個資料庫中,盡量避免產生分散式事務。那麼業界普遍的做法是通過用戶維度來進行拆分。由於不同的實體id的值不同,且不能保證每個實體和請求中都包含用戶id,所以簡單的用實體id或用戶id進行hash取模將不能保證同一個用戶的數據都落在同一個分片。
我們的做法是在用戶創建的時候給該用戶隨機或一定規則(如地區)生成一個兩位的分片號00~99(兩位意味著可以分成百庫百表,通常夠用了),那麼在生成與該用戶相關的所有實體的id的時候都約定把這個分片號拼接到這個id中。那麼在分散式數據訪問框架中進行路由選擇時就可以取id中的分片號進行路由,而不依賴於用戶id。且在排查問題的時候也非常方便定位數據的存儲位置。
下面是一個參考的id生成規則示例:
所以數據水平拆分除了需要一個強大的分庫分表數據訪問中間件,還需要一個分散式序列生成器。當然這個生成器也可以是集成在分庫分表數據訪問中間件中的一個功能。
那麼如果一筆交易涉及多個用戶按誰的id來拆分呢?比如一筆轉賬或支付,涉及轉出方/轉入方或支付方/收款商戶。這種情況我們一般按資金轉出方來拆分。
分散式改造後帶來了哪些問題,如何應對
1. 分散式事務產生
由於按用戶維度進行了分庫分表,可能存在跨資料庫的事務,比如說轉賬交易中轉出方和轉入方的賬戶不在同一個資料庫中,這就產生了分散式事務。通常我們不會用XA協議來解決,因為XA協議鎖資源性能太差,通常是通過TCC柔性事務來解決。
2. 跨表查詢如何解決?
由於分庫分表後,不能進行跨庫的連表查詢,原來的一些很常見的查詢操作變得很麻煩。對於不是以用戶為維度的匯總查詢也非常麻煩。比如說支付交易流水是按發起方用戶(支付方)進行拆分的,用戶需要查詢自己的賬單很容易。但是商戶要查詢賬單就比較麻煩了,要去所有的庫里遍歷、匯總、分頁。也非常耗系統資源。所以一般會做一些數據冗餘,比如說螞蟻內部是專門做了一個賬單系統,通過消息隊列非同步將用戶的交易流水同步過來,T+1跑批再按商戶維度進行拆分,並生成商戶賬單。查詢帳單都從帳單系統中查詢。
還可以通過異構索引來查詢和做OLAP分析,異構索引就是將數據同步到ElasticSearch,利用ES的強大索引能力來做查詢和分析,為了使業務更容易使用,可以利用數據訪問代理層來屏蔽底層是路由到資料庫還是路由到ES。
3. 如何進行數據同步?
企業都有做大數據分析的需求,需要將數據同步大數據平台,如hadoop,分庫分表之後,數據同步會比較複雜,畢竟之前是單表同步到 hadoop比較簡單,但是100張表同步到hadoop里會複雜一些。
我們需要有一套數據模型管理平台,數據模型、分庫分表規則等由這個平台來管理,當需要使用數據的時候通過(應用/邏輯表)維度訂閱數據即可,不用單獨訂閱物理表。不僅是數據同步,凡是有業務需要用到各種數據,都可以通過這個平台來訂閱,幫助企業數據業務快速發展。
4.分庫分表後批處理任務怎麼處理?
批處理任務,比如有日終對賬、清算、生成賬單等,原來在一個資料庫中的時候,由一個應用Server去資料庫中撈取流水就可以了。但是分庫分表後流水都落在很多庫里,一個Server去每個庫里遍歷顯然不是一個很好的辦法,且不能充分利用機器資源,提高批處理效率,甚至由於處理的數據量太大在日終低峰期內根本無法完成任務。
前面提到各條流水數據之間沒有關聯的,完全可以並發的進行處理,每個Server撈取一個分片的數據進行處理。那麼就需要有一個很好的調度系統來協調,可以採用三層調度的方式。
圖:三層調度示意圖
- 第一層split:把任務按照分片規則拆分成多個Load任務,並發送到集群中的Server去執行。
- 第二層load:每個load任務撈取一個分片的數據,逐條創建execute任務,並發送到集群中的Server去執行。注意:撈取數據要進行流量控制以免數據量太大把集群打滿。
- 第三層execute:執行具體的一條數據的邏輯。
三層架構並不是說一定都需要三層,可以根據業務邏輯來定製只有兩層也可以。
5. 如何進行數據擴容?
通常我們會採用「預分配」的方式來做,即一開始我們就按一個比較長期的容量來規劃分片數,比如百庫百表,但實際上一開始並沒有這麼大的量,所以實際只有兩個資料庫Server,在這兩個Server上分別建50個schema,邏輯上扔然是100個分庫,物理上只有2個資料庫Server,當容量不夠的時候,為了保證數據的均衡,我們通常會採用成倍擴容的方式,再加兩台資料庫Server,然後分別遷移25個schema到這兩個資料庫Server上,數據也搬過來,由於數據同步有延時,全量數據同步完成後,兩邊的schema都禁寫,待增量數據同步完成後打開新的schema寫,會產生短暫的部分用戶交易失敗,重試一下即可,在低峰期做遷移,產生小範圍失敗一般是可以接受的。由於邏輯分片數沒有變化,擴容成本比較低。我們通常不會用改變分片規則的方式來擴容,因為改變分片規則需要進行數據重新分布,成本和風險巨大。
6. 如何進行容災?
- 同城容災:通常可以同城多機房部署應用,資料庫只有一個機房處於Active狀態,所有機房的應用都連這個機房的資料庫,另一個機房的資料庫為備庫,進行主備複製,當備機房發生災難時業務不會中斷,但業務會跌一半,當主機房發生災難時,資料庫切換備庫,會有短暫的業務中斷。
- 異地冷備:應用也是異地多機房部署,由於異地網路延時不可忽略,異地備機房是處於standby狀態,正常是沒有流量的,冷備機房採用資料庫主備同步的方式同步數據,這種方式災備切換時間長,成本投入高。
- 異地多活:應用採用異地多機房單元化部署架構,每個機房的應用都是可以提供服務的,單元內是自包含部署全量應用,每個單元服務多個分片的用戶,單元化架構可以參考《素描單元化》。由於異地網路延時是不可忽略的,數據層的容災方案也是分「流水型」、「狀態型」、「配置型」數據採用不同的容災策略。具體可參考《分散式系統數據層設計模式》。
7. 如何更好的排查和分析問題?
分散式改造後整個系統架構已經是服務化了,原來通常可以通過查本地日誌來定位問題。但現在一個交易由若干個系統協同完成,我們需要一套分散式鏈路跟蹤系統或APM(應用性能管理)系統來協助我們看清整個系統的全貌,分析排查問題。那麼如何進行分散式鏈路跟蹤呢?可以通過opentracing標準對整個分散式架構中的中間件和應用進行埋點或自動植入探針實現。
總結
分散式架構有著海量、成本、穩定、速度的優勢,但它也不是銀彈,分散式改造是一個非常複雜的工程,需要熟悉業務,設計出整個系統的業務架構,按照業務架構來進行垂直拆分。需要熟悉數據模型,區分「流水型」、「狀態型」、「配置型」數據,根據不同類型數據的特點將它他按用戶維度進行拆分。
熟悉分散式中間件的運用,分散式中間件在整個分散式架構中起著至關重要的作用,將技術構架與業務結合起來。整個改造需要公司內部下定決心,All in的方式進行。螞蟻金服通過十五年五代金融級架構的演進,多年雙11的考驗,形成了一套業界領先的金融級分散式架構。
— END —
< 粉絲福利時間 >
恭喜以下用戶您獲得『螞蟻金服科技』粉絲福利:雲棲2050門票一張
xyzlab、空、Limo、覔亖甴、Joe-姜忠坷、純、成崽兒、聖愛、魔方、Monte、山在北國、dk、Mystery、莫那·魯道、德 立、0.0、成東青、欲 亂 人 心 、笑吧、軍軍軍軍
請獲獎的用戶添加螞蟻小助手微信號:Ant-Techfin01
回復「2050門票」然後領取您專屬的兌換碼
購票官網:https://www.yunqi2050.org/#/index
非常感謝大家對螞蟻金服技術的支持和關注!
如有問題,我們將隨時為您答疑解惑
後續小螞蟻會努力給您帶來更多福利哦~
推薦閱讀:
※分散式系統設計:單點模式之挎斗模式
※阿里雲表格存儲負載均衡實踐
※ZEROC究竟是何方神聖?
※分散式系統設計:服務(多節點)模式
TAG:支付系統 | 螞蟻金服浙江螞蟻小微金融服務集團有限公司 | 分散式系統 |