互聯網金融系統的核心是支付結算,而支付結算的基礎又是帳戶系統。互金帳戶系統的特色是併發量大、響應快、交易金額大,熱點帳戶問題突出。一個合格的帳戶系統既要解決上述問題,又必須絕對保證資金安全。做爲宜信這家互聯網金融公司的支付結算中心,其帳戶系統也必須具有上述特徵。前端
宜信支付結算帳戶體系是客戶、用戶、帳戶三層結構,證件號和證件類型惟一肯定一個客戶,客戶號和機構號肯定一個用戶,一個用戶下可開多個不一樣類型的帳戶。如圖:nginx
帳戶系統的基礎是帳戶,全部的操做都圍繞着帳戶進行,帳戶包含如下一些屬性:redis
帳戶下掛在最底層的會計科目下,會計科目決定了帳戶的含義及餘額變更方向。會計科目的一些屬性以下:sql
宜信支付結算帳戶系統採用科目樹的概念,每一個機構都會綁定一個科目樹。科目樹的根節點是一級科目,底層的科目下掛帳戶,結構以下:數據庫
宜信支付結算帳戶系統採用公司自研的分佈式微服務框架,對外提供http json接口,內部各服務間採用redis實現的消息隊列通信。json
宜信支付結算帳戶系統分爲接入模塊、記帳子系統、開戶子系統、異步記帳模塊、查詢子系統、定時任務子系統、日終子系統、異步日誌模塊,下圖是帳務系統功能模塊圖:緩存
記帳處理是帳戶系統的核心功能,該功能對性能的要求比較高,高併發下熱點帳戶問題比較突出,資金的正確性也必須保證,而且根據業務不一樣,記帳的分錄也是五花八門,宜信支付結算帳戶系統如何應對這些問題,這裏重點介紹下:安全
熱點帳戶問題是帳戶系統的痛點,也困擾了咱們好久,這裏着重說下。網絡
-- 充值時的記帳分錄是:架構
借方:三方支付待清算帳戶(+)
貸方:我的餘額帳戶(+)
當大量用戶充值時,三方支付的待清算帳戶就是熱點帳戶,頻繁的增長餘額。
-- 提現時的記帳分錄是:
借方:我的餘額帳戶(-)
貸方:三方支付資產帳戶(-)
當大量用戶提現時,三方支付的資產帳戶就是熱點帳戶,頻繁的減小余額。
--業務收服務費的記帳分錄是:
借方:我的帳戶(-)
貸方:商戶服務費帳戶(+)
當大量向用戶收取服務費時,商戶服務費帳戶就是熱點帳戶,會頻繁增長餘額。
--業務服務費付款的記帳分錄是:
借方:商戶服務費帳戶(-)
貸方:我的帳戶(+)
當大量用服務費餘額向用戶付款時,商戶服務費帳戶就是熱點帳戶,會頻繁減小余額。
記帳時,全部涉及的帳戶餘額都要作update更新,高併發狀況下,當出現上述類型的熱點帳戶時,因爲數據庫的行級鎖,對同一帳戶的更新餘額操做由並行變成串行,單個請求的響應時間變長,從而拖垮整個記帳服務。
宜信支付結算帳戶系統針對上述問題作了以下處理:
咱們把熱點帳戶按照金額變更方向分爲加頻帳戶(餘額增長頻繁)、減頻帳戶(餘額扣減頻繁)、雙頻帳戶(餘額增長扣減均頻繁)。
準實時更新餘額。先將金額變更插入臨時表中,由定時任務按照必定頻率彙總發生額,並更新帳戶餘額,然後刪除臨時記錄。當加頻帳戶減錢餘額不足時,主動去彙總發生額。這裏須要考慮主動彙總發生額和定時任務處理的併發狀況,咱們在該定時任務執行時設置redis鎖,防止併發,主動彙總時會去判斷這個redis鎖是否存在,如存在證實定時任務正在執行,無需主動彙總,多是真的餘額不足。主動彙總一樣會設置redis鎖,定時任務一樣會判斷。
將減頻帳戶拆分多個子帳戶,減頻子帳戶設置金額報警,若是某個減頻子帳戶餘額不足觸發報警,會對該子帳戶作資金歸集,將其餘子帳戶餘額歸集到該子帳戶(每一個子帳戶設置可歸集金額限制)。如在交易過程當中發現該子帳戶餘額不足,轉向使用其餘子帳戶記帳。因爲拆分子帳戶,餘額查詢時須要彙總各個子帳戶餘額返回;記錄主帳戶流水須要記帳後餘額,這裏須要異步計算彙總。當減頻帳戶加錢時,須要平均分配入帳到不通的子帳戶。
將雙頻帳戶拆分多個子帳戶。加錢時,準實時更新餘額,先將子帳戶金額變更插入臨時表中,由定時任務按必定頻率彙總發生額,將彙總的發生額更新進對應的子帳戶,並刪除金額變更記錄;減錢按照以前減頻帳戶的邏輯執行。
高併發狀況下,當多個帳戶以前互相轉帳時,可能會出現死鎖問題。
例如:A餘額帳戶 —> B餘額帳戶(線程1) 和 B餘額帳戶—>A餘額帳戶(線程2) 兩個轉帳請求併發,帳戶系統對每一個轉帳請求都會更新A、B餘額,這兩個更新須要在一個事務裏,正常流程線程1先更新A,再更新B,線程2先更新B,再更新A,線程1更新完A後會等待B的鎖,不提交事務,線程2更新完B後會等待A的鎖,不提交事務,這樣兩個線程互相等待鎖,形成死鎖。
宜信支付結算帳戶系統針對這種狀況提出瞭解決辦法,對帳戶號進行排序後再更新餘額,這樣每一個線程都是先更新A再更新B,解決了死鎖問題。
宜信支付結算帳戶系統數據庫採用Mysql,緩存採用redis。
Mysql數據庫採用主從架構,一主二從,主庫向從庫同步數據。針對一些數據量大的表進行分表,比較有表明性的是帳戶流水錶,既要按帳戶維度查詢,又要按時間維度彙總,因此針對這個特色,冗餘了一張表,一張按照帳戶分表,一張按照日期分表。
Redis採起集羣架構,集羣中每一個點主備的形式。
帳戶系統各個服務部署在同一機房,其中記帳子系統和異步記帳模塊部署在4個不一樣的物理機上,其餘子系統和模塊部署在2個不一樣物理機上。最前端採用nginx實現負載均衡。
做者:李銳 程留允