高併發賬戶記錄查詢

【摘要】 面對高併發賬戶記錄查詢問題,按照本文的介紹一步一步操作,就能有效提升性能。點擊瞭解高併發賬戶記錄查詢

問題描述

高併發賬戶記錄查詢在銀行、互聯網企業、通信企業中廣泛存在。例如:網上銀行、手機銀行、電商個人賬戶查詢、互聯網遊戲賬戶等等。這類查詢有三個共同點:

1、 數據總量非常大。用戶數量本身就非常多,再加上多年的賬戶數據,數據量可以達到幾千萬甚至上億條。

2、 訪問人數衆多。幾百萬甚至上千萬人訪問,屬於高併發查詢。

3、 不能讓用戶等待。手機、網頁要達到秒級響應,否則嚴重影響用戶體驗。

下面以某銀行賬戶活期明細查詢爲例,給出這類問題的解決辦法。

某銀行共一億個活期賬戶,每個賬戶平均每月有 7 條數據,每年數據總量 84 億條。每條數據中的機構字段,還要關聯分支機構表(幾千條)記錄。在性能上,要求單臺服務器支持一千個以上的查詢,響應時間不能超過 1 秒。

有序行存

活期明細數據隨着時間增長非常快,一年就有 84 億條。如果放到內存中,需要大量內存空間,硬件投入成本太高,所以要放到硬盤上存儲。分支機構表只有幾千條數據,可以放在內存中存儲。

在硬盤上存儲,要考慮是行存還是列存。列存數據分塊壓縮,能減少遍歷數據量。但由於賬戶查詢是隨機的,整塊讀取會有額外解壓計算。而且每次取數都針對整個分塊,複雜度較高,性能不如行存。因此,這個場景要選擇行存存儲,如下圖:

圖 1:行存和列存

具體的實現可以採用 Java、C++、SPL 等高級語言。這裏我們以代碼量最少的 SPL 語言爲例講解。

代碼示例 1

A1:連接生產數據庫,用遊標讀取活期存款數據,按照賬戶 id 排序。

A2:建立本地組表文件。

A3:建立組表,並從數據庫遊標讀取活期存款明細數據,寫入文件。

其中,A3 中的 @r 選項,就是建立行存文件。一年 84 億條數據都導出,時間會比較長。但是這是一次性的工作,後續就只需要追加增量數據即可。增量數據的追加方法,後面會有介紹。如果按照賬戶排序會對生產數據庫造成較大壓力,可以導出之後基於文件排序。排序使用 SPL 的 sortx 函數,具體用法參見函數參考。

利用索引

要利用索引提速,先要對明細文件建立索引。由於明細數據量大,建立的索引文件也會很大。很難全部加載到內存中。可以建立多級索引,如下圖:

圖 2:多級緩存

還是以 SPL 爲例,建立多級索引,只需要在“代碼示例 1”的基礎上,增加一個網格即可:

代碼示例 2

A4:對行存文件建立索引文件。

加載的索引級別越多,佔用存儲空間越大。同時,賬戶 id 的跨度變小,加載到內存中後,索引效果也會變好。查詢時可以根據內存大小,儘可能加載更多級別的索引,可以有效提高查詢速度。

在查詢之前,系統初始化或者數據變動時,要預先加載多級索引,以 SPL 代碼爲例:

代碼示例 3

A1:判斷全局變量中是否存在 detailR,如果存在,表示已經加載了索引。

B1:如果全局變量中沒有 detailR,那麼打開組表加載三級索引。@2 或者 @3 表示加載 2 或者 3 級索引。

B2:detailR 存入全局變量。

這段預先加載的初始化代碼(代碼示例 3),可以保存成 init.dfx,放入集算器主目錄(main path),在節點機(unitServer)啓動的時候會自動被調用,如下圖:

圖 3:節點機自動調用初始化代碼

由於我們提前準備好的活期數據是對賬戶 id 物理有序的,查詢時根據索引找到賬戶 id 後,可以在硬盤連續讀取,顯著減少磁盤 IO,有效提速,如下圖:

圖 4:索引和有序行存

查詢賬戶 10100,先利用內存中預先加載的多級索引和索引文件,快速定位到活期明細數據文件中的位置,再連續讀取到賬戶 id 有變化爲止。因爲數據是按照賬戶 id 物理有序的,所以文件的其他位置不可能再有 10100 賬戶的數據了。

利用索引查詢的示例代碼如下:

代碼示例 4

A1:全程變量 detailR 已經緩存了三級索引,現在可以基於它利用索引,按照條件取出賬戶爲 10100 的記錄。

每個賬戶的數據量並不大,所以可以全部讀入內存。

活期明細前端應用(網頁或者 APP),要通過集算器的 JDBC 驅動調用 SPL 代碼查詢。調用的時候,需要將賬戶 id 作爲參數傳給 SPL 程序。例如:定義一個網格參數 countid,傳入賬戶 id 爲 10100。A1 中的代碼就要改爲:=detailR.icursor (;ID==countid,index_detailR_id).fetch()。

關聯查詢

查到指定賬戶數據裝入內存後,可以將機構數據也讀入內存。在內存中關聯計算,性能可以得到保障。示例代碼如下:

代碼示例 5

A2:讀入機構數據。

A3:賬號 10100 的活期明細數據關聯機構數據。

A4:將賬戶 id、分支機構名稱和金額返回給前端調用者(網頁或者 APP)。

機構數據可以在應用系統初始化的時候加載入內存,不必每次讀取,查詢速度更快。在上面提到的 init.dfx 中增加代碼如下:

代碼示例 6

預先加載機構數據之後,查詢代碼要在“代碼示例 5”的基礎上去掉加載機構數據的部分,修改之後的查詢代碼如下:

代碼示例 7

A2:直接用預先加載的全程變量 corp 和活期明細數據關聯計算,省去了每次查詢加載機構數據的時間。

數據更新

活期明細存款是按賬號有序的,並不是按日期有序。所以,不能在末尾追加當日新增數據。活期明細幾十億條,如果每天有序歸併新數據的話,耗時太長。每月歸併一次的方案比較理想。如果將活期明細數據看成是主文件,那麼更新原理如下圖:

圖 5:數據更新

數據更新的示例代碼如下:

代碼示例 8

A1、B1:如果是每月 1 日,重整文件。

A2:從生產數據庫中讀入當日數據。

A3:將當日數據有序歸併到集算器自動生成的補文件中。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章