编程知识 cdmana.com

區區一個SpringBoot問題就被幹趴下了,看完這一篇就够了!

系統介紹

整個系統可以從功能上分為3塊:

  1. 業務系統:在上遊有很多的業務系統,業務系統的運行產生很多的數據,這些數據分散在很多的數據庫中,大部分是MySQL數據庫
  2. 數據智能平臺:數據智能平臺屬於中臺系統,主要為業務系統提供强大的數據支撐服務,下層連接數倉。
  3. 數據倉庫: 數據倉庫統一集中的管理所有的數據,數倉會將業務系統產生的數據按天進行加工、抽取、轉換到數據倉庫存儲。

當一天結束後,各個業務系統產生了大量的數據,這些數據由定時任務進行加工、抽取到數據倉庫存儲,當半夜你還在睡覺的時候,這些定時任務就在默默的運行著。

區區一個SpringBoot問題就被幹趴下了,看完這一篇就够了!_後端

而每天加工的數據通常要求在上班工作時間之前加工完成,然後通過數據智能平臺的查詢系統供業務系統查詢調用,這一次數據沒有查詢到是因為在第二天早上10點,數據還沒有加工完成。下面就是找問題優化了,因為正常來講,即使定時任務鏈再長,也不會慢到第二天10點鐘數據還沒有出來。下面就是找問題,然後進行優化了。

任務優化

通過任務日志發現有一個上遊系統的數據抽取執行時間有3個小時,而數據量僅100萬。當然,光憑這樣還無法確定這個任務是否是可以被優化的。

查看任務代碼,邏輯還比較簡單:有一張原始數據錶,記錄商品信息以及定義的分類(這一點是虛構的,實際情况要複雜一些,我這裏精簡然後轉換了一下,便於理解),而數倉的目標錶是將分類和商品分別存儲在不同的錶中,大致結構如下。

區區一個SpringBoot問題就被幹趴下了,看完這一篇就够了!_Java_02

那為什麼需要進行這樣的轉換呢? 這是因為整個大的系統,一般來說只能定義一些基本的規範,而具體的細節規範則無法約束,比如A系統的身份證字段名稱為card_no,而B系統的身份證字段名稱為crdt_no(這種情况大家應該經常遇到);再比如處理實體關系的時候,處理方式也是不同的,1對1的關系,可以建兩張錶關聯,也可以一張錶都存儲,這就造成了多個系統的不統一性,而這種情况是不可避免的,因為從業務系統來說,都保證了系統的正常運行。

而數倉對多個原始數據處理的時候就需要考慮到兼容的問題,所以就會出現如上圖的轉換過程。

而這個任務執行3個小時的原因在於原始錶中的一條記錄,會轉換到數倉錶中的三張錶中,而且這三張錶是通過id進行關聯,整個代碼流程如下。

區區一個SpringBoot問題就被幹趴下了,看完這一篇就够了!_程序員_03

然而問題來了,100萬的數據,跑了3個小時,然後我開始嘗試去優化程序的執行流程,大概從一下幾點入手

  1. 將分類緩存,分類在系統中已經固定,不會發生變化,緩存可以减少查詢數據庫的次數
  2. 每次從原錶中讀取的數據更多,從原來的500/次 -> 2000/次

經過優化,效率有一些提昇,但並不是很明顯(有同學可能要問了,這些都是很基本的,為什麼最開始做? 咳咳。。。這個嘛,曆史原因吧,在最開始數據可能不多,不論以什麼方式執行,都差別不大,比如執行10分鐘和執行20分鐘,看似2倍的執行效率,但是由於沒有影響到業務系統,且一直正常運行,也就沒有看出問題)。

這裏數據是需要關聯的,所以我們是需要插入數據並拿到這條記錄的自增長id,然後插入到關聯錶,而錶結構基本不可能去動的(錶結構動了那真是牽一發而動全身了,第二天准得被叫去喝茶)。

區區一個SpringBoot問題就被幹趴下了,看完這一篇就够了!_後端_04

那麼我們先來分析一下這裏為什麼執行這麼慢呢。

  1. 原錶100萬的數據,每次查詢出2000條,所以查詢的總次數就是1000000/2000 = 500次,這肯定消耗不了多少時間。這裏基本沒有優化的空間,就算一次全部查詢出來,也僅僅節省499次的查詢時間(也不可能一次查詢這麼多數據)
  2. 查詢的2000條數據,數據轉換,然後依次插入到信息錶以及關聯錶中,這裏是一條一條解析執行的,總計插入數據庫4000次,毫無疑問,這裏是最耗時的。數據轉換是必須的,而且是在內存中操作,所以耗時不是特別多;那麼剩下的就是總計100萬 * 2的數據庫插入次數,能否進行優化呢?

首先想到的就是批量插入,批量插入可以有效的降低數據庫訪問次數。但是這裏不能進行批量插入是因為需要取到自增長id,感覺陷入了困境。

區區一個SpringBoot問題就被幹趴下了,看完這一篇就够了!_程序員_05

當天晚上昨晚運動之後,拋開煩惱,覺得渾身舒坦。

區區一個SpringBoot問題就被幹趴下了,看完這一篇就够了!_後端_06

突然,腦袋靈光一閃,數據庫的自增長id是由數據庫控制的數值,而自增長的步長我們是知道的,比如自增長步長為1,當前自增長id為1的話,那麼可以肯定,下一條記錄的自增長id就為2,以此類推。

那是否可以插入一條記錄,取到自增長id,然後就可以計算出之後所有數據的自增長id,而不再需要每條記錄都去取自增長id了。

但是這樣也有一個問題,就是在數據轉換導入的過程中,不能有其他的程序向錶中插入數據,不然會導致程序計算的自增長id匹配不上。而這個問題根本不存在,因為數倉的數據都是由原始錶計算插入的,在同一時間是沒有其他的任務寫這張錶,那麼我們就可以放心大膽的幹了。

最後

金三銀四到了,送上一個小福利!

 CodeChina開源項目:【一線大廠Java面試題解析+核心總結學習筆記+最新講解視頻】

區區一個SpringBoot問題就被幹趴下了,看完這一篇就够了!_程序員_07

區區一個SpringBoot問題就被幹趴下了,看完這一篇就够了!_程序員_08

區區一個SpringBoot問題就被幹趴下了,看完這一篇就够了!_程序員_09

版权声明
本文为[Android我愛死你了]所创,转载请带上原文链接,感谢
https://cdmana.com/2021/09/20210915061928882t.html

Scroll to Top