支付結算系統如何應對高並發、熱點帳戶等問題

2019-09-16     IT技術分享
\t文章來源:網絡

網際網路金融系統的核心是支付結算,而支付結算的基礎又是帳戶系統。金融帳戶系統的特點是並發量大、響應快、交易金額大,熱點帳戶問題突出。一個合格的帳戶系統既要解決上述問題,又必須絕對保證資金安全。作為宜信這家網際網路金融公司的支付結算中心,其帳戶系統也必須具備上述特徵。

一、帳戶體系

1.1 帳戶結構

宜信支付結算帳戶體系是客戶、用戶、帳戶三層結構,證件號和證件類型唯一確定一個客戶,客戶號和機構號確定一個用戶,一個用戶下可開多個不同類型的帳戶。如圖:

1.2 帳戶屬性

帳戶系統的基礎是帳戶,所有的操作都圍繞著帳戶進行,帳戶包含以下一些屬性:

  • 會計科目:每個帳戶金額的變動要體現一些會計的屬性,以便會計核算。
  • 帳戶類別:分為個人帳戶、企業帳戶、平台類帳戶。
  • 帳戶明細:帳戶的明細是反映帳戶餘額變動的每筆詳情,採用複式記帳法,包含本對方帳號、帳戶等信息、摘要、借方的發生額及餘額等信息。
  • 帳戶餘額:記錄帳戶的實時餘額。

1.3 會計科目

帳戶下掛在最底層的會計科目下,會計科目決定了帳戶的含義及餘額變動方向。會計科目的一些屬性如下:

  • 科目類別:資產類、負債類、所有者權益、成本類、損益類等。
  • 科目級別:會計科目的級別,一級科目、二級科目、三級科目等。下級科目歸屬上級科目。
  • 餘額方向:標示餘額是在借方還是貸方。
  • 科目的期末餘額:每日日切後會匯總底層科目所有下掛帳戶在上一會計日的餘額總和,上級科目匯總下級科目的餘額總和。

1.4 科目樹

宜信支付結算帳戶系統採用科目樹的概念,每個機構都會綁定一個科目樹。科目樹的根節點是一級科目,底層的科目下掛帳戶,結構如下:

二、帳戶系統架構

宜信支付結算帳戶系統採用公司自研的分布式微服務框架,對外提供http json接口,內部各服務間採用redis實現的消息隊列通訊。

2.1 帳戶系統功能架構

宜信支付結算帳戶系統分為接入模塊、記帳子系統、開戶子系統、異步記帳模塊、查詢子系統、定時任務子系統、日終子系統、異步日誌模塊,下圖是帳務系統功能模塊圖:

  • 接入模塊:提供報文解析、驗簽、參數校驗、權限認證等公共服務,是帳戶系統的統一入口。
  • 異步日誌模塊:異步記錄業務系統請求報文。
  • 記帳子系統:帳戶系統的核心模塊,處理業務系統的記帳請求。
  • 開戶子系統:處理業務系統的開戶請求。
  • 首次開立帳戶:為個人或企業開立客戶、用戶及提前配置的默認開通的帳戶。
  • 指定開立帳戶:個人或企業在首次開立帳戶後,可按科目號指定開立帳戶。
  • 查詢子系統:提供帳戶、記帳的一些查詢功能。
  • 異步記帳模塊:提供異步記錄帳戶流水的功能。
  • 定時任務子系統:處理失敗重試、熱點帳戶等的定時任務。
  • 日終子系統:提供日切以及日終跑批的功能。

2.1.1 記帳處理

記帳處理是帳戶系統的核心功能,該功能對性能的要求比較高,高並發下熱點帳戶問題比較突出,資金的正確性也必須保證,並且根據業務不同,記帳的分錄也是五花八門,宜信支付結算帳戶系統如何應對這些問題,這裡重點介紹下:

  • 帳戶系統記帳採用記帳服務的概念,每個記帳服務就是一個記帳分錄的模板,業務系統按照這個模板傳入記帳金額、帳戶號或者用戶號等信息。
  • 帳戶系統採用redis分布式鎖,防止業務系統重複提交請求。設置記帳訂單防重表,按照請求單號和機構號對記帳請求做冪等性校驗。
  • 採用複式記帳法,按照會計規則按照借貸記錄流水,有借必有貸。
  • 記帳處理時,更新帳戶餘額後同步返回結果給業務系統,異步的處理記帳流水。同時設置補償機制,定時重試記帳流水處理失敗的訂單,重試三次失敗後報警人工介入。
  • 記帳規則處理,每個記帳服務可以綁定一些記帳規則,帳戶系統根據記帳服務遍歷其綁定的規則,順序處理。

2.1.2 熱點帳戶問題

熱點帳戶問題是帳戶系統的痛點,也困擾了我們很久,這裡著重說下。

-- 充值時的記帳分錄是:

借方:三方支付待清算帳戶(+)

貸方:個人餘額帳戶(+)

當大量用戶充值時,三方支付的待清算帳戶就是熱點帳戶,頻繁的增加餘額。

-- 提現時的記帳分錄是:

借方:個人餘額帳戶(-)

貸方:三方支付資產帳戶(-)

當大量用戶提現時,三方支付的資產帳戶就是熱點帳戶,頻繁的減少餘額。

--業務收服務費的記帳分錄是:

借方:個人帳戶(-)

貸方:商戶服務費帳戶(+)

當大量向用戶收取服務費時,商戶服務費帳戶就是熱點帳戶,會頻繁增加餘額。

--業務服務費付款的記帳分錄是:

借方:商戶服務費帳戶(-)

貸方:個人帳戶(+)

當大量用服務費餘額向用戶付款時,商戶服務費帳戶就是熱點帳戶,會頻繁減少餘額。

記帳時,所有涉及的帳戶餘額都要做update更新,高並發情況下,當出現上述類型的熱點帳戶時,由於資料庫的行級鎖,對同一帳戶的更新餘額操作由並行變成串行,單個請求的響應時間變長,從而拖垮整個記帳服務。

宜信支付結算帳戶系統針對上述問題做了如下處理:

我們把熱點帳戶按照金額變動方向分為加頻帳戶(餘額增加頻繁)、減頻帳戶(餘額扣減頻繁)、雙頻帳戶(餘額增加扣減均頻繁)。

  • 加頻帳戶處理

准實時更新餘額。先將金額變動插入臨時表中,由定時任務按照一定頻率匯總發生額,並更新帳戶餘額,而後刪除臨時記錄。當加頻帳戶減錢餘額不足時,主動去匯總發生額。這裡需要考慮主動匯總發生額和定時任務處理的並發情況,我們在該定時任務執行時設置redis鎖,防止並發,主動匯總時會去判斷這個redis鎖是否存在,如存在證明定時任務正在執行,無需主動匯總,可能是真的餘額不足。主動匯總同樣會設置redis鎖,定時任務同樣會判斷。

  • 減頻帳戶處理

將減頻帳戶拆分多個子帳戶,減頻子帳戶設置金額報警,如果某個減頻子帳戶餘額不足觸發報警,會對該子帳戶做資金歸集,將其他子帳戶餘額歸集到該子帳戶(每個子帳戶設置可歸集金額限制)。如在交易過程中發現該子帳戶餘額不足,轉向使用其他子帳戶記帳。由於拆分子帳戶,餘額查詢時需要匯總各個子帳戶餘額返回;記錄主帳戶流水需要記帳後餘額,這裡需要異步計算匯總。當減頻帳戶加錢時,需要平均分配入帳到不通的子帳戶。

  • 雙頻帳戶處理

將雙頻帳戶拆分多個子帳戶。加錢時,准實時更新餘額,先將子帳戶金額變動插入臨時表中,由定時任務按一定頻率匯總發生額,將匯總的發生額更新進對應的子帳戶,並刪除金額變動記錄;減錢按照之前減頻帳戶的邏輯執行。

2.1.3 記帳死鎖問題

高並發情況下,當多個帳戶之前互相轉帳時,可能會出現死鎖問題。

例如:A餘額帳戶 —> B餘額帳戶(線程1) 和 B餘額帳戶—>A餘額帳戶(線程2) 兩個轉帳請求並發,帳戶系統對每個轉帳請求都會更新A、B餘額,這兩個更新需要在一個事務里,正常流程線程1先更新A,再更新B,線程2先更新B,再更新A,線程1更新完A後會等待B的鎖,不提交事務,線程2更新完B後會等待A的鎖,不提交事務,這樣兩個線程互相等待鎖,造成死鎖。

宜信支付結算帳戶系統針對這種情況提出了解決辦法,對帳戶號進行排序後再更新餘額,這樣每個線程都是先更新A再更新B,解決了死鎖問題。

2.2 帳戶系統存儲層架構

宜信支付結算帳戶系統資料庫採用Mysql,緩存採用redis。

  • Mysql資料庫採用主從架構,一主二從,主庫向從庫同步數據。針對一些數據量大的表進行分表,比較有代表性的是帳戶流水錶,既要按帳戶維度查詢,又要按時間維度匯總,所以針對這個特點,冗餘了一張表,一張按照帳戶分表,一張按照日期分表。
  • Redis採取集群架構,集群中每個點主備的形式。

2.3 帳戶系統的網絡層架構

帳戶系統各個服務部署在同一機房,其中記帳子系統和異步記帳模塊部署在4個不同的物理機上,其他子系統和模塊部署在2個不同物理機上。最前端採用nginx實現負載均衡。

end:如果你覺得本文對你有幫助的話,記得關注點贊轉發,你的支持就是我更新動力。

文章來源: https://twgreatdaily.com/zh-cn/HrblOm0BJleJMoPMkCk3.html