如何解决数据一致性、任务调度、流水号生成等问题?
互聯網金融是最近幾年的長期風口,它經歷了野蠻生長期,目前處于強監管期,2016 年 8 月 24 日出臺的《網絡借貸信息中介機構業務活動管理暫行辦法》中明確要求“網絡借貸信息中介機構應當實行自身資金與出借人和借款人資金的隔離管理,并選擇符合條件的銀行業金融機構作為出借人與借款人的資金存管機構。”
截至 2017 年 5 月 17 日,正常運營平臺共有 396 家正常運營平臺宣布與銀行簽訂直接存管協議,約占同期 P2P 網貸行業正常運營平臺總數量的 17.89%,其中有 209 家正常運營平臺與銀行完成直接存管系統對接并上線,占 P2P 網貸行業正常運營平臺總數量的 9.44%。這就意味著 2017 年 8 月份之后,可能 80% 多的 p2p 平臺(約 2000 家平臺)都要面臨淘汰或者整改。因為,除了對平臺的體量規模有要求,還對平臺的技術實力也是一次大考驗。
首先人人聚財平臺采取的是直接存管形式,直接存管才是真正符合《暫行辦法》要求的銀行資金存管的方式,在這種模式下,客戶的資金不在平臺流轉,能夠有效隔離平臺與投資人的資金,平臺全程無法觸碰資金,杜絕了資金池的產生。
人人聚財于 2016 年 10 月底上線銀行存管系統,已穩定運行 8 個多月,每天處理異步消息 200 萬條,峰值 400 萬條,人人聚財的技術架構經過了 1.0 版本的所謂的巨石(Monolith)系統,發展到了 2.0 版的分布式版本,整體技術架構如下圖所示:
在此架構下,我們來看看,實現銀行存管的過程中有哪些關鍵點。
數據一致性如何解決?訂單化機制
平臺每天都與銀行有著非常頻繁的交互,如何保證平臺與銀行之間的數據一致呢?這個問題本質上是屬于分布式事務的問題,業界一般的解思想方案有:2PC(兩階段提交)、TCC(Try/Confirm/Cancel)、事務消息等等,這些方案優缺點本文不作涉及,我們來看看人人聚財是如何應對這一問題的。
我們知道,分布式應用具有 CAP 特性,一般來講,不論電商,類電商,還是社交應用,都會適當犧牲 C,保證最終一致 (Eventually Consistency)和 AP,我們的做法是平臺與銀行的所有接口進行交互均采用訂單化機制。
我們把每一個與銀行的操作交互抽象為一個訂單,訂單化機制就是指交互開始的時候平臺插入 N(N>=1)個訂單, 這 N 個訂單根據業務的不同可能是一個父的訂單,也可能是父子模式的訂單,每當接口或業務完成的時候就更新對應的訂單的業務狀態。
當交互期間因網絡或其他原因導致掉單時,平臺的補單機制可以及時根據當前訂單的業務狀態來判斷接下來應該從哪里開始補單。比如說在給用戶賬戶進行返現時由于網絡原因導致超時了,那么補單機制會先去銀行查詢該訂單的狀態,根據業務處理狀態來進行下一步操作;若由于銀行系統異常處理失敗了,那么補單機制會自動更換流水號重新發起請求,整個交互過程如下圖所示:
?定時數據核對
平臺每天晚上固定時間點會主動核對平臺用戶賬戶的可用余額、凍結金額等數據,并與銀行的用戶賬戶數據進行比對,對于有異常數據會及時通知到相關責任人進行排查。
?對賬
對于涉及到資金交互的系統,對賬是必不可少的。平臺每天固定時間點會主動去銀行獲取前一天的對賬文件,與平臺數據進行核對。
流水號如何生成?
在與銀行的交互過程中,必須使用一個唯一的流水號來標識一次請求操作,不然業務操作會亂作一團,在對比了一些優秀的唯一 ID 生成算法后,最終選擇使用 Twitter 的 Snowflake 算法來為我們提供銀行存管中的流水號服務。此算法的好處有兩點:一是純數字,二是整體上來說是按時間順序的。
原理不作過多介紹,網絡上的文章也很多,算法原版是 Scala 寫的,網上也有 Java 版本,但是有 bug,會產生重復的 ID,無法用于生產環境的集群部署,我對其進行了修改,修改后,可用于生產環境,已穩定運行 8 個月,下面是完整核心代碼:
https://gist.github.com/xishuixixia/f0f8684805d0504289b7a40f3b327dd6
需要注意的是,集群機器需關閉 NTP 的時間同步功能,至于原因,留給讀者,看上面代碼便知。
任務調度平臺如何落地?
在金融行業中,一定會存在大量定時任務,即在一個特定的時間點,系統執行指定的一個或多個業務邏輯,諸如跑批,對賬等等。
?為什么要用任務調度平臺
業界優秀的調度框架當屬 Quartz,比較成熟,但是它有一個不足,就是任務的執行和調度嚴重耦合,代碼里面有很多硬編碼,很容易出 bug,因此構建一個任務調度平臺就顯得很有必要。
?怎樣搭建任務調度平臺
指導原則是輕量化,不需要太重,我們在 Quartz 的基礎上,將任務調度行為抽象形成“調度中心”公共平臺,而平臺自身并不承擔業務邏輯,“調度中心”按照調度配置發出調度請求。“調度”應用和“任務執行”應用之間用 HTTP 協議進行通訊,因此,“調度”和“任務執行”兩部分相互解耦,提高系統整體穩定性和擴展性;即使某個任務執行模塊宕機也不會影響其它業務。整體架構如下圖所示:
我們業務模塊只需要提供“任務執行”接口,任意部署到一臺機器上,然后調度任務平臺配置調用業務接口的基本 Meta 信息(如調用地址端口,bean 名字,監控報警郵件地址)即可。需要注意的是,我們在開發“任務執行”接口必須保證四個特性:
可重復執行:即冪等性, 數學表示為:f(f(x))=f(x), 在此處是指調度模塊執行多次,不會影響業務本身邏輯。
可延遲執行:如果調度任務在指定的時間沒有調度。可以通過手動執行來彌補。業務執行結果和指定時間執行的結果一致。
可并發執行:如果調度任務同時調用 A B 兩臺業務服務(處理相同業務)。這個時候需要我們業務需要保證事務一致性。
可暫停、可恢復執行:隨時可以暫停正在執行的任務,也可以恢復繼續執行。
當然業界也有一些比較優秀的任務調度系統,在此不作對比。
如何提升性能
下面以定投寶(人人聚財平臺專有的一款智能投顧產品,以下簡稱定投寶)債權轉讓業務為例來具體說明。
平臺每天都有一部分定投寶產品到期,需要將本金和利息返還給用戶。在用戶購買了平臺的定投寶產品且定投寶復審通過后,用戶的資金就會匹配并投資到對應的借款項目中去。而由于定投寶的期限相對于借款項目來說較短,以及兩者的到期時間不一樣,因此在定投寶到期的時候借款項目并未到期,因此定投寶只有將用戶持有的債權轉讓出去之后才可以退出,才能將資金返還給用戶。
在匹配之初,基于為用戶的投資風險考慮,用戶投資定投寶的資金被打散成很小的粒度分散投資到不同的借款項目中去了,因此在定投寶到期需要退出的時候會有大量的債權需要轉讓出去。在接入銀行之前,平臺只需要處理自身的數據即可。而在接入銀行之后,平臺嚴重依賴銀行的操作結果。接入之初,定投寶債權轉讓需要經歷兩個階段,一個是出讓,用于業務校驗,另一個是轉讓,進行轉讓動作。其中出讓是同步接口,轉讓是異步接口。
經過壓力測試和數據觀察發現大部分時間都消耗在出讓階段,這種模式下無法滿足平臺業務峰值下的業務要求。于是,在與銀行多次溝通討論的情況下,銀行取消了出讓接口。同時平臺自身也優化了定投寶債權轉讓模塊,通過 MQ 來接收異步回調消息、代碼重構、優化相關的 SQL 語句以及由原本的單線程模式轉為線程池模式,大大的提高了業務處理效率。
通過上面這個例子,我們知道平臺主要通過以下幾個方面來提高業務處理性能:
-
數據庫層面:優化 SQL 語句,提高執行效率;
-
代碼層面:優化代碼結構,使用線程池來提高并行處理能力,使用 MQ 來對系統進行解耦并提高異步處理能力;
-
業務層面:在業務的合理性與效率方面進行權衡,對不合理的接口 say no。
http://mp.weixin.qq.com/s/FNBoppyJKF4t-TqxIzOsfg
總結
以上是生活随笔為你收集整理的如何解决数据一致性、任务调度、流水号生成等问题?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 天价切糕电视剧完整版(天价切糕)
- 下一篇: 爱的支撑(说一说爱的支撑的简介)