1. 程式人生 > >從宜人貸系統架構看網際網路高併發對金融系統架構的挑戰

從宜人貸系統架構看網際網路高併發對金融系統架構的挑戰

原文:http://www.p2pquan.com/article-740-1.html

一、簡介

隨著網際網路金融的持續火熱,越來越多的銀行紛紛釋出了各自的網際網路金融產品。但是網際網路產品“高併發、大資料量”的特點卻對於銀行傳統的核心繫統架構帶來了新的挑戰。

1、網際網路的核心技術特徵

當前網際網路的核心技術特徵主要可以概括為:分散式,易擴充套件,大量低端裝置,底層開源軟體。分散式結構可以通過平行擴充套件來支撐網際網路上蜂擁而至的訪問客戶。同時,基於客戶行為分析的大資料平臺也需要分散式系統來完成,其中最典型的就是Hadoop叢集。

2、傳統銀行系統的技術特徵

傳統銀行系統的技術特徵主要可以概括為:專用裝置、底層閉源軟體,成本昂貴,系統穩定。由於金融業對核心系統的穩定性、可靠性和安全性要求極高,目前大部分銀行都是採用IBM

的整體解決方案,並且幾乎沒有可替代性,IBM仍然保持著市場壟斷地位。

3、挑戰主要來自客戶體驗的升級

隨著網際網路客戶規模的增長,客戶行為和系統響應次數也呈現爆發式增長。

傳統電子銀行提供的是被動服務,產品只提供相應的功能,需要客戶自己去查詢和操作;而網際網路產品更多的是提供主動服務,形象直觀的展現客戶相關資料資訊。這就要求單個客戶發起的或者產品自動發起的一次請求響應需要同時與核心系統的多個功能介面進行互動,再考慮網際網路客戶規模效應,其對系統的壓力是非常大的,由此也會帶來巨大的風險。

4、產品設計應具備合理性

大多數情況下,核心系統的架構是無法改變的。這就需要我們從產品設計和應用系統上儘量規避高併發互動響應的發生,但這絕不是以犧牲客戶體驗為代價來完成的。

如果核心繫統因為高併發量而出現瓶頸時,首先應當保證應用系統對產品的支撐,至少產品不能出現崩潰和給客戶帶來超出預期的失落感;其次,產品的異常提示內容也要足夠友好,可以減少客戶的負面情緒。最後,對發起請求的總量進行控制,可以採用臨時輸入驗證碼等方式來降低客戶請求的頻率。

下面以“宜人貸系統架構”為例,宜人貸架構師孫軍著重地分享介紹了宜人貸系統發展過程中遇到的實際問題和解決的辦法,並重點介紹宜人貸出借系統和借款系統的高併發解決方案。

二、宜人貸系統版本的迭代

1.0 版本——簡單的煩惱

迭代之前宜人貸的系統,其實就是一個前臺,一個後臺,一個DB,前臺採用的是多級部署的方式。

軟體也是跟最傳統的軟體一樣分三層,第一層是Controller

,第二個是Service,第三層是DB。顯然這個系統並不適合網際網路,有一些難以避免的問題。首先當用戶過萬,線上使用者上線的時候,這樣的部署方式會產生一些瓶頸,包括伺服器和資料。第二個就是團隊變大,所有開發人員集中針對同一個系統,衝突嚴重。

1.5版本——“吃大補”試試!

為了上面的問題他們做了一些修改,孫軍把它定義成“吃大補”。吃大補通常有一個很明顯的特點,就是立馬見效,但是副作用也很大。

首先,他們在宜人貸的頁面層更加關注效能,比如說瀏覽器,壓縮傳輸,頁面都經過了Yslow的優化,瀏覽層增加了CDN,做了靜態化甚至反向代理,這樣可以抵擋80%的流量。

頁面層中間加了一個叢集,這個叢集基本上可以擋掉80%流量,最後系統把它業務垂直拆分成多個系統,比如說APP的後臺,Web、信審、抓取、活動、報表等等。資料庫也有一些變化,開始只是一臺主機,一臺資料庫,現在變成了主從,一主多從。

使用者可以撐到過戶百萬,除此之外他們的制約在資料庫,兩套系統分別擋掉了4/5的流量,整體擋掉後其流量變成了以前的1/25,其實就是資料庫併發能力來說擴大了25倍。但是他們的業務發展遠遠不止25倍,所以資料庫依然是一個很大的瓶頸。

再者、第二個問題就是團隊劃分,其實每個團隊都做自己的系統,但是宜人貸仍然使用同一個資料庫,這個時候比如說設計和修改資料庫的時候,都非常麻煩。每次都要問一下其他團隊,我這麼改行不行,對你有什麼影響等等。

另外、第三個問題也非常棘手,大量使用了快取,資料的時效性和一致性的問題越來越嚴重。我記得4月份的時候上了一個理財產品,它的庫存多退了一倍,10點鐘上線非常準時,但是發現問題之後把它下線,下了半天之後下不了,原因就是有快取,非常難下。

2.0版本——“開小灶”精細化

為了解決1.5T,孫軍他們需要做精細化的優化,他把它定義成開小灶。

首先,合理劃分資料歸屬、優化查詢效率、縮短資料庫事物時間;其次,分系統,每個系統用固定的表。從每天都在做的事中,讓運維找出線上最慢的有哪一些,從而對它們做優化。第三,做去事物,或者儘可能的提升縮短事物的時間。

然後、開始關注程式碼質量,提高執行效率,並且開始關注併發問題;使用者達到這個量的時候,就會有有使用者幫他們測試。打一個比方同一個使用者用同一個帳戶登入了兩個客戶端,他同時點進去,這個時候如果程式處理的不好,很有可能讓他提兩次。 最後,要區分強一致與最終一致,合理使用快取與讀寫分離來解決這些問題。

2.0效能問題解決很多了,還會帶來新的問題——系統越來越多,系統間依賴關係變得複雜;這個時候很容易出現A調B,B調C的迴圈呼叫。第二個是系統間互相呼叫增多,上游系統壓垮下游系統;第三個,也是非常頭疼的問題,系統很多,查詢線上問題變得越來越困難;試想一下當系統部署到很多機器上,想找一個線上的問題,通過查日誌的形式非常難查。所以在這個基礎上他們做了幾件事,一是關於限流,限流通常基於兩點:最大活動執行緒數(高消耗任務),每秒執行次數(低消耗任務);

活動最大執行緒數適合於高消耗的任務,然後每秒執行次數適合於低消耗的任務(這裡應該是針對請求介面次數做的限制吧)。 二是一個建議,他建議儘可能統一內部系統間返回值,返回值中一定要記錄返回狀態(業務正常、業務異常、程式異常)和錯誤說明;第三個,可配合RPC框架完成限流工作。

再說一下關於查詢問題,宜人貸日誌系統部署框架,最左側的是他們的業務系統,在業務系統上把日誌蒐集到卡夫卡佇列,最終採用Kibana和他們自己研發的系統去檢視日誌,日誌到了一個集中點不容易找,而這樣就更好找了。

關於軟體方面,宜人貸統一使用slf4j+logback輸出日誌,然後日期系統做到日誌串聯,所有服務端和客戶端之間都隱藏的一些引數,這些引數會隨著呼叫鏈一步一步往下傳,通過AOP來實現,日誌串聯需要傳遞哪一些引數,或者日誌中到底要打哪一些引數呢?第一個是時間,這個時間應該到毫秒級,第二個是流水號,流水號就是每次請求昇華到唯一的一個P值。然後是裝置號:時間(到毫秒)、流水號(uuid,每次請求生成唯一值)、使用者session、裝置號、呼叫者時間(APP使用手機本地時間)、本機IP、客戶端IP、使用者真實IP、跨越系統次數——有了這些找問題就非常容易。

做到2.0之後,宜人貸的網站基本上到了中大型的網站,短時間內不會有太多的效能問題了,但是他們肯定還得繼續往下走。

3.0版本——拆分做服務化

3.0總結下來就是要做服務化,通俗一點說就是拆分,包括垂直拆分,充值拆分基礎上系統之上的水平,那麼服務化要怎麼做呢。

首先,做業務拆分的時候,可以按照基礎服務和業務服務先做一個大的服務的拆分,然後基礎服務又包括無業務型的基礎服務和有業務型的基礎服務,這些系統非常明顯的跟其他的系統沒有太大的關係。業務型基礎服務的特點就是跟業務之間的關係很小,就是這些系統跟業務系統之間的關聯關係只是主鍵和外來鍵的關聯關係。

宜人貸可以天然地拆卸分成兩大系統,一個是貸款業務,一個是理財業務,貸款業務可以拆卸成後臺、Web、合作渠道,這個系統之下會有一個基礎服務,就是提供一些基礎服務和介面的一個系統。

基礎服務拆成了兩部分,一個是基礎服務的進件,一個是服務售後。然後拆分過程中他們又發現一個問題,理財和貸款有兩個業務怎麼拆都拆不開,就是撮合業務和債券關係,這種拆不開的可以單獨再提升一個功能服務來提供服務就可以了。

拆分的系統看起來好像很容易,拆分的辦法孫軍總結了如下幾個:

第一,適當冗餘,冗餘確保資料庫依然可以關聯查詢;大部分時間並不是做一個全新的系統,而是在原來系統之上做修改,這個時候可以做一些冗餘,保證他們可以不修改。

第二,資料複製,但必須保證資料歸屬系統有修改和發起複製的許可權;這個比較適合於剛才說的全域性配置,比如說宜人貸的所有公司都會有這麼一個整合表,記錄了全國的區線,這些在每個系統中都會用,不一定每個系統都以介面的形式呼叫他。可以在每個系統裡面都冗餘。

第三,就是如何驗證資料庫——並不一定非把它拆分成兩個驗證它,可以一個數據庫上建兩個帳號,這兩個帳號分別的許可權指向拆分之後的表,可以通過帳號直接驗證拆分效果。

第四,提前規劃服務,拆卸之前確定一下區分讀多、寫多服務,區分快請求、慢請求服務,不同服務需要分開部署。

最後,同一資料不能由超過一個以上的系統控制,同一系統不能由超過一個以上的負責人負責。

4.0版本——雲的展望

做到以上幾點, 3.0版本已經做的差不多了,但是後面宜人貸依然還有很多要做的,4.0版本是不是要做雲平臺,異地部署的方案,表很大的時候是不是要做垂直拆分,去IOE或者使用Docker快速部署等等這些,這些其實都是我們做4.0或者5.0將來要考慮的事情。

三、宜人貸理財系統的優化

合理預估流量——強一致與最終一致

圖中這三個介面分別為首頁、列頁,詳情頁。

首先要合理預估流量,區分出什麼是強一致性的流量,什麼是非強制性的引流。

評估方法一:平日PV*(24/熱度時間);

評估方法二:熱度時間內線上使用者數*平均每人操作次數/熱度時間。以宜人貸理財端為例,他們在高時期有2萬人,然後平均做20次操作,在2分鐘左右基本上就把所有的債券搶光了,翻番出來大概是3000多次每秒。

然後要區分什麼是強一致,什麼是最終一致,這兩個流量分別是多少。強一致這個資料必須是最準確的資料,這個數字不能用讀寫分流的形式保留,必須是正確的資料。最終的資料就是時效性沒有那麼高,只要最後的結果是一致的就可以。

20次操作包含:註冊、註冊驗證碼、登陸、解鎖手勢密碼、首頁、瀏覽產品列表等等這些操作,這裡面其中有一些比如說產品餘額、生成訂單、支付簡訊、付款,這些都是非常強一致的要求,這個大概佔每個運算元的佔1/7左右,翻算出來是約500次/S。

針對最終一致的方案非常簡單,增加機器就可以解決,時效性較高的可以直接使用資料庫的讀寫分離,增加應用伺服器,處理更多的併發; 實時性較高使用讀寫分離方案、縮短catched時間;實時性較低的可以使用較長時間catched。

強一致性的流量處理方案,總的來說就是加速,可以使用資料庫的鎖,也可以使用ZK,或者直接使用排隊的機制,這裡面數據庫的鎖,基本上變化在2000次每秒以下。在這個情況之下,完全可以使資料庫的鎖來防止併發,第一個方法就是有事務的防止併發的方法。

然後再更新共享資源,最後再查詢一次共享資源,然後判斷一下結果。假如說這個結果是成立的,就直接執行,假如說這個結果是不成立的,那麼再做。第二個就是無事物下的方法,加一個條件去判斷他們的資源成不成立,當沒有更新成功的時候,就返回。

如果流量依然承受不住該怎麼辦?

做到這些其實已經能夠承受非常大的流量,但是業務可能繼續發展,還承受不住怎麼辦呢?

首先的一個原則就是沒有任何分散式的操作,最好的方法就是單點、排隊處理。

第二,單點併發過大,使用合適的方式拆分鎖的粒度;比如說產品12月期的,增加一個9月期的,6月期的等等。比如說增加這個還不夠,能不能按省賣他們的產品,每個省有一個自己的庫存,粒度會很多。

第三,增加降級需求,不影響使用者正常使用情況下可以適當降低服務質量。適當修改需求、適當增加使用者等待結果時間;如果讓使用者等2秒,是不是能撐到4400每兩秒,答案是肯定的,可以多讓使用者等一段時間,這個互動上讓使用者有更好的體驗。 最後適當調整運營策略,分散使用者集中活躍時間。