1. 程式人生 > >10億級訂單系統分庫分表設計思路

10億級訂單系統分庫分表設計思路

一、背景

隨著公司業務增長,如果每天1000多萬筆訂單的話,3個月將有約10億的訂單量,之前資料庫採用單庫單表的形式已經不滿足於業務需求,資料庫改造迫在眉睫。

二、訂單資料如何劃分

我們可以將訂單資料劃分成兩大型別:分別是熱資料和冷資料。

  • 熱資料:3個月內的訂單資料,查詢實時性較高;

  • 冷資料A:3個月 ~ 12個月前的訂單資料,查詢頻率不高;

  • 冷資料B:1年前的訂單資料,幾乎不會查詢,只有偶爾的查詢需求;

可能這裡有個疑惑為什麼要將冷資料分成兩類,因為根據實際場景需求,使用者基本不會去檢視1年前的資料,如果將這部分資料還儲存在db中,那麼成本會非常高,而且也不便於維護。另外如果真遇到有個別用戶需要檢視1年前的訂單資訊,可以讓使用者走離線資料檢視。

對於這三類資料的儲存,目前規劃如下:

  • 熱資料: 使用mysql進行儲存,當然需要分庫分表;

  • 冷資料A: 對於這類資料可以儲存在ES中,利用搜索引擎的特性基本上也可以做到比較快的查詢;

  • 冷資料B: 對於這類不經常查詢的資料,可以存放到Hive中;

三、MySql 如何分庫分表

3.1、按業務拆分

在業務初始階段,為了加快應用上線和快速迭代,很多應用都採用集中式的架構。但是隨著業務系統的擴大,系統匾額越來越複雜,越來越難以維護,開發效率變得越來越低,並且對資源的消耗也變得越來越大,通過硬體提高系統性能的成本會變得更高。

通常一般的電商平臺,包含了使用者、商品、訂單等幾大模組,簡單的做法是在同一個庫中分別建4張表,如下圖所示:

但是隨著業務的提升,將所有業務都放在一個庫中已經變得越來越難以維護,因此我們建議,將不同業務放在不同的庫中,如下圖所示:

由圖中我們可以看出,我們將不同的業務放到不同的庫中,將原來所有壓力由同一個庫中分散到不同的庫中,提升了系統的吞吐量。

3.2、分庫與分表

我們知道每臺機器無論配置多麼好它都有自身的物理上限,所以當我們應用已經能觸及或遠遠超出單臺機器的某個上限的時候,我們惟有尋找別的機器的幫助或者繼續升級的我們的硬體,但常見的方案還是通過新增更多的機器來共同承擔壓力。

我們還得考慮當我們的業務邏輯不斷增長,我們的機器能不能通過線性增長就能滿足需求?因此,使用資料庫的分庫分表,能夠立竿見影的提升系統的效能,關於為什麼要使用資料庫的分庫分表的其他原因這裡不再贅述,主要講具體的實現策略。

(1)分表策略

我們以訂單表為例,在訂單表中,訂單id肯定是不可重複的,因此將該欄位當做shard key 是非常適合的,其他表類似。假設訂單表的欄位如下:

1create table order(2 order_id bigint(11) ,3

我們假設預估單個庫需要分配100個表滿足我們的業務需求,我們可以簡單的取模計算出訂單在哪個子表中,例如: order_id % 100,

這時候可能會有人問了,如果我根據order_id 進行分表規則,但是我想根據user_id 查詢相應的訂單,不是定位不到哪個子表了嗎,的確是這樣,一旦確定shard key,就只能根據shard key定位到子表進而查詢該子表下的資料;如果確實想根據user_id 去查詢相關訂單,那應該將shard key設定為user_id, 那分表規則也相應的變更為: user_id % 100;

(1)分庫實現策略

資料庫分表能夠解決單表資料量很大的時候資料查詢的效率問題,但是無法給資料庫的併發操作帶來效率上的提高,因為分表的實質還是在一個數據庫上進行的操作,很容易受資料庫IO效能的限制。

因此,如何將資料庫IO效能的問題平均分配出來,很顯然將資料進行分庫操作可以很好地解決單臺數據庫的效能問題。

分庫策略與分表策略的實現很相似,最簡單的都是可以通過取模的方式進行路由。

我們還是以order表舉例,

例如:order_id % 庫容量,

如果order_id 不是整數型別,可以先hash 在進行取模,

例如: hash(order_id) % 庫容量

(3)分庫分表結合使用策略

資料庫分表可以解決單表海量資料的查詢效能問題,分庫可以解決單臺數據庫的併發訪問壓力問題。有時候,我們需要同時考慮這兩個問題,因此,我們既需要對單表進行分表操作,還需要進行分庫操作,以便同時擴充套件系統的併發處理能力和提升單表的查詢效能,就是我們使用到的分庫分表。

如果使用分庫分表結合使用的話,不能簡單進行order_id 取模操作,需要加一箇中間變數用來打散到不同的子表,公式如下:

中間變數 = shard key %(庫數量*單個庫的表數量);2庫序號 = 取整(中間變數/單

例如:資料庫有10個,每一個庫中有100個數據表,使用者的order_id=1001,按照上述的路由策略,可得:

這樣的話,對於order_id=1001,將被路由到第1個數據庫的第2個表中(索引0 代表1,依次類推)。

三、整體架構設計

從圖中我們將請求分成read和write請求,write請求比較簡單,就是根據分庫分表規則寫入db即可。

對於read請求,我們需要計算出查詢的是熱資料還是冷資料,一般order_id生成規則如下,“商戶所在地區號+時間戳+隨機數”,我們可以根據時間戳計算出查詢的是熱資料還是冷資料,(當然具體業務需要具體對待,這裡不再詳細闡述)

另外架構圖中的冷資料指的是3個月~12個月前的資料,如果是查詢一年前的資料,建議直接離線查hive即可。

圖中有一個定時Job,主要用來定時遷移訂單資料,需要將冷資料分別遷移到ES和hive中。