1. 程式人生 > >在實踐中使用ShardingJdbc元件的正確姿勢(一)

在實踐中使用ShardingJdbc元件的正確姿勢(一)

在網際網路時代,隨著業務數量的暴增和應用規模的不斷擴大,無論是oracle還是mysql這樣子的關係型資料庫,都會面臨伺服器CPU、磁碟IO和記憶體的各種瓶頸問題。基於此情況,各個業務團隊迫切需要一種資料分片的方案將業務資料量儲存成本分攤到成本可控的各個普通資料庫伺服器上,資料庫切分的方案便應運而生。

由於之前釋出的一篇文章《記一次使用ShardingJdbc切分資料庫表的SpringBoot工程實踐》評論中,有部分同學覺得還沒有結合實際情況來進行場景深度分析與介紹,讓讀者還無法完全理解為何需要選用開源ShardingJdbc元件和選用其構建業務系統帶來的一些優勢。因此,寫本文意在結合實際的業務場景進行分析,詳細闡述選型開源元件—ShardingJdbc時候的一些思考,並最終給讀者呈現業務系統整合ShardingJdbc的最終設計方案。另外,本文僅為使用開源元件ShardingJdbc第一篇幅,後續篇幅還將繼續介紹開源元件ShardingJdbc的一些其他進階用法。

一、資料的切分方式

一般,線上系統的業務量不是很大,比如說單庫的資料量在百萬級別以下,那麼MySQL的單庫即可完成任何增/刪/改/查的業務操作。隨著業務的發展,單個DB中儲存的資料量(使用者、訂單、計費明細和許可權規則等資料)呈現指數級增長,那麼各種業務處理操作都會面臨單DB的IO讀寫瓶頸帶來的效能問題。

(1)垂直切分方案

這時候,我們會考慮使用對之前的整個單DB採用垂直資料切分的方案,根據不同的業務型別劃分庫表,比如訂單相關若干表放在訂單庫,使用者相關的表放在使用者庫,賬務明細相關的表放在賬務庫等。這樣就將資料分擔到了不同的庫上,達到專庫專用的效果。

使用垂直切分方案的主要優點如下:

a.拆分後業務清晰,符合微服務的總體設計理念;

b.子系統之間的整合與擴充套件相對容易;

c.按照不同的業務型別,將不同的庫表放在不同的資料庫伺服器上,便於管理;

d.根據業務資料的“冷”、“熱”狀態,採用不同的快取和資料庫模式設計方案;

垂直切分的缺點如下:

a.跨庫的Join查詢,需要使用不同子系統的API介面讀取後在記憶體中完成關聯查詢,提高系統複雜度;

b.如果某一種型別的業務呈現爆發式地增長,該業務對應的庫表還是會存在單DB的IO讀寫的瓶頸問題,從這一點來說垂直切分並未從根本解決單庫單表資料量過大的問題;

c.存在跨庫事務的一致性問題,解決起來比較麻煩,當然也可以採用分散式事務來解決;

(2)水平切分方案

由於本文主題講的是利用開源元件ShardingJdbc進行資料水平切分的實踐,因此對於垂直切分方案的一些細節問題就不做過多的詳細介紹了。與垂直切分對比,這裡講的水平切分不是將庫表根據業務型別進行分類儲存,而是將其按照資料表中某個欄位或某幾個欄位的某種規則切分儲存至多個DB中,在每個庫每個表中所包含的只是其中的一部分資料,所有庫表加起來的才是全量的業務資料。

這種對資料的切分方式,基本可以保證經過水平切分後的單庫單表儲存的容量不會太大,從而保證了對單表的增/刪/改/查的SQL執行效率和處理能力。其中,資料的分片規則也是需要重點考慮的,因為它會使得資料分片在多個庫表中是否均勻分佈儲存。然而,資料水平切分方案為業務系統帶來福音的同時也給系統構建帶來了一些值得思考的問題。

使用水平切分方案的主要優點如下:

a.單庫單表的資料容量可以維持在一個量級,有助於提高業務SQL的執行效率和系統性能;

b.不管是利用ShardingJdbc元件還是MyCat框架,業務系統的應用層涉及改造得都較少,只需要根據實際的業務情況來設計資料分片的路由規則即可;

c.可以提高業務系統的穩定性和負載能力;

使用水平切分方案的主要缺點如下:

a.資料水平切分後,分佈在多庫多表中,跨庫Join查詢比較複雜;

b.分片資料的一致性較為難保證;

c.對於歷史資料的遷移和資料庫的擴容需要較大的維護工作量;

二、選型ShardingJdbc元件的分析與思考

對於,“流水”/“明細”一類的業務資料,通常的業務需求是準實時或者說相對滯後,這些資料是按小時、按日和按月彙總加工處理後生成最終業務需求的資料(比如使用者賬單、報表和話單)。此外,由於這一型別的業務資料量普遍較大,比如清算系統的清分明細、雲管平臺的資源計量明細、訂單系統的訂單流水和雲端計算主機資源上報的效能資料等,如果只是使用單庫單表儲存的普通方案,那麼在單表資料量達到千萬級別以上的時候,單庫的IO讀寫能力將持續降低,會成為業務系統整體吞吐量和效能的瓶頸。

對於上述的問題,有一些對DB較為熟悉的同學第一時間想到的解決方案,可能會是MySQL的分割槽表。MySQL的分割槽表比較適合用於解決業務資料具有較強時間序列特點,且資料量偏大的場景。但是,如果SQL的查詢條件並非基於時間維度的,那麼執行起來的效率並不會有所改觀,同時對於處理單表千萬級別以上資料量時,MySQL的分割槽表方案還是會顯得有些“力不從心”。

對於以上這種“流水”/“明細”類的業務資料,作者還是推薦使用水平切分的方案從根本上來解決業務上遇到的單表資料過大的問題。由於該型別的業務資料基本不會涉及跨庫的Join連表SQL查詢、只需保證分庫的本地事務,且並不會遇到上面水平切分方案中的幾個需要考慮的問題,對於這樣子的業務場景可以考慮使用水平切分的方案。那麼,我們應該選擇哪一款開源的分庫分表元件,又或者是根據業務情況來自己定製化研發呢?

(1)選型分庫分表中介軟體的分析

如果業務系統設計之初打算採用水平切分方案的話,那麼有必要好好思考下如何來選型分庫分表的中介軟體。在當前的開源元件中比較流行的兩款分別為ShardingJdbc和MyCat。

ShardingJdbc這款分庫分表元件代表了客戶端類的分庫分表技術框架,其定位為輕量級資料庫驅動,可以由Spring Boot這樣的業務工程直接快速整合,以jar包形式提供服務,無需額外部署和其他依賴。對於業務系統的開發人員與資料庫運維人員無需改變原有的開發與運維方式。在2.X版本中,採用"半理解"理念的SQL解析引擎,以達到效能與相容性的最大平衡。因此,ShardingJdbc即為增強版的JDBC驅動,其優勢在於無需對原有的業務工程進行任何改造的基礎上,即可使其擁有分庫分表的能力,成本較低,易於上手。但是,也有缺點,中介軟體與業務應用工程繫結在一起,對應用本身有侵入。並且目前只支援Java語言,問題難以追蹤。

而MyCat是一個開源的分散式資料庫系統(屬於代理類框架),相當於一個實現了MySQL協議的資料庫代理伺服器。使用者可以使用MySQL客戶端工具和命令列訪問,而其後端使用MySQL原生協議與多個MySQL資料庫伺服器通訊,也可以用JDBC協議與大多數主流資料庫伺服器通訊。其分庫分表的方案優點在於,能夠處理非常複雜的需求,不受資料庫訪問層原來實現的限制,擴充套件性強且對於應用服務透明且沒有增加任何額外負載。其缺點是上線部署需要額外的中介軟體,增加運維成本;應用服務需經過代理來連線資料庫,網路上多了一層連結的開銷,效能有損失且有額外風險。

(2)使用ShardingJdbc解決的基本業務場景

選擇ShardingJdbc元件後,就需要使用該元件來解決實際的問題。這一節主要根據之前提到的“流水”/“明細”一類的業務資料,同時結合ShardingJdbc元件的特點來進行一定的分析,使得讀者對正確使用ShardingJdbc元件進行業務系統水平切分有一定的瞭解。

前面已經提到了“流水”/“明細”類的業務資料,一般是準實時或者說相對滯後,需要按小時、按日和按月彙總處理後生成最終的業務資料(如賬單、報表和話單等)。我們對“流水”/“明細型”業務資料處理過程中,一般都會涉及資料落庫(Insert SQL)、資料分組彙總和分組查詢(Select+sum(xxx)+Group By SQL)以及刪除資料表(Delete SQL)等業務處理操作。這裡有必要對這幾種型別的SQL進行一定的說明:

a. 資料落庫(Insert SQL):流水/明細類的資料一般都需要先DB持久化處理;以雲端計算平臺中10W臺虛擬機器同時產生效能明細資料上報,如果是單庫單表,則這個資料庫會進行每小時會有10W次的寫請求;如果使用100個分表(分10個庫,每庫10個表)則每個表平均承受1000次寫請求,每個庫平均分擔1W次的請求壓力,這樣子就可以將原來單庫單表的寫請求壓力成倍的減少;一般業務研發人員使用ShardingJdbc元件,設定合理的資料分片路由規則,即可使得流水/明細類的資料基本均勻落在我們預先設定的分庫分表中。

b. 資料分組彙總查詢(Select+sum(xxx)+Group By SQL):由於(a)中持久化至分庫分表的業務資料為若干段時間的業務資料,根據業務需求還需要按日,按周或者按月進行累加彙總,因此有必要對各個分表中的資料執行Select+sum(xxx)+Group By的分組彙總SQL;ShardingJdbc元件可以完成SQL的解析、改寫、路由和結果歸併,對於“Select+sum(xxx)+Group By SQL”的語句,可以遍歷設定的多個分庫分表,對每個分庫分表執行SQL後進行一個結果歸併再返回給業務呼叫方。

c. 刪除資料表(Delete SQL):一般業務系統對會通過定時任務來生成明細資料加工處理後的業務資料(比如使用者賬單、清償明細、雲資源按日按月的話單)。一旦生成這些有效業務資料後,原來落庫的明細也就沒有什麼業務價值,可以通過任務定期刪除或者遷移至歷史庫的方式來使得分庫分表的資料水位量級維持在一定量,因此就需要涉及對原來儲存在分庫分表的明細資料進行刪除;ShardingJdbc元件可以根據“Delete SQL”語句中的篩選條件進行規則路由來定位某個分庫和分表,否則會刪除所有分庫中的分表資料。

三、業務系統整合ShardingJdbc的架構設計

根據上面對“流水”/“明細”型業務資料的場景分析,基本可以畫出SpringBoot業務工程整合分庫分表元件ShardingJdbc的架構設計圖:

從上面業務系統架構設計圖中可以看出,明細型業務資料(比如之前提的,清算系統的清分明細、雲管平臺的資源計量明細、訂單系統的訂單流水和雲端計算主機資源上報的效能資料明細)根據設定的資料分片路由規則先落庫至sharding_db00~sharding_db04五個分庫的對應分表中。然後,利用ShardingJdbc元件對分組彙總查詢SQL的解析、改寫、路由和歸併結果的能力,分別對五個庫中對應業務分表中的資料彙總累加求出每天/每月同一個使用者下的資源計費累加值。最後,將這些“加工”後的業務資料批量插入至共享庫share_db中,其他定時任務再從共享庫中讀取並生成最終形式的業務資料(比如,按月的賬單、話單或者效能計量值)。其中,對於異常情況(明細流水異常、彙總異常和系統異常等),需要將其儲存至共享庫中的異常資訊表中。另外,在明細落庫之前還需要考慮冪等前置校驗的問題。對於ShardingJdbc元件的分庫分表路由規則可以參照下圖:

從上面的分庫分表路由規則圖上可以看出,預先設定了通過客戶id來路由定位至分庫,通過使用者id來路由定位至分表。這裡,由原來的單庫單表分成五個庫的多分表(每個庫中均有test_msg_queue_bill_record0~test_msg_queue_bill_record4五個分表,這裡只是示例,在真實的業務場景下需要根據業務資料的總體容量來設定分庫分表的規模,究竟是分5個庫每個庫5表,還是分10個庫每個庫10表來滿足業務要求)。在一般情況下,如果執行的SQL為“select * from test_msg_queue_bill_record”就能借助ShardingJdbc元件來遍歷查完5個分庫中的test_msg_queue_bill_record0~4五個分表,無需我們自己來做分庫分表的遍歷查詢了。

四、總結

本文先介紹了目前兩種資料切分的主要方案(垂直切分和水平切分)及其優缺點。根據“流水”/“明細”類別的資料切分業務場景,闡述了業務系統設計之初選型分庫分表元件的分析,並介紹瞭如何利用ShardingJdbc來解決“資料落庫(Insert SQL)”、“資料分組彙總查詢(Select+sum(xxx)+Group By SQL)”和“刪除資料表(Delete SQL)”的幾種基本業務場景。最後,給出業務系統整合ShardingJdbc元件後的架構設計方案。本文僅僅使用了Sharding-Jdbc元件的核心功能來解決了一部分基本的業務場景問題。ShardingJdbc元件還有其他很多高階的功能(比如讀寫分離、最大努力送達型的柔性事務、分片路由規則動態配置和資料庫治理和ShardingProxy等,ps:聽@亮哥說,ShardingJdbc 3.0起可以完美支援Batch Insert SQL,很是期待),限於篇幅將在後續的文章中結合對應的場景進行介紹。限於筆者的才疏學淺,對本文內容可能還有理解不到位的地方,如有闡述不合理之處還望