10億級別訂單分庫分表解決方案

背景

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

訂單數據如何劃分?

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

  1. 熱數據:3個月內的訂單數據,查詢實時性較高。
  2. 冷數據A:3個月 ~ 12個月前的訂單數據,查詢頻率不高。
  3. 冷數據B:1年前的訂單數據,幾乎不會查詢,只有偶爾的查詢需求。

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

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

  1. 熱數據: 使用mysql進行存儲,當然需要分庫分表
  2. 冷數據A: 對於這類數據可以存儲在ES中,利用搜索引擎的特性基本上也可以做到比較快的查詢。
  3. 冷數據B: 對於這類不經常查詢的數據,可以存放到hive中

MySql 如何分庫分表

一、按業務拆分

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

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

10億級別訂單分庫分表解決方案

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

10億級別訂單分庫分表解決方案

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

二、分庫與分表

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

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

1)、分表策略

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

1create table order(

2 order_id bigint(11) ,

3 user_id bigint(11),

4 phone varchar(15),

5 ...

6)

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

10億級別訂單分庫分表解決方案

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

2)、分庫實現策略

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

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

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

我們還是以order表舉例,

例如:order_id % 庫容量,

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

例如: hash(order_id) % 庫容量

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

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

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

1中間變量 = shard key %(庫數量*單個庫的表數量);

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

3表序號 = 中間變量%單個庫的表數量;

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

1中間變量 = 1001 %(10*100)= 1;

2庫序號 = 取整(1/100)= 0;

3表序號 = 1%100=1;

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

10億級別訂單分庫分表解決方案

整體架構設計

10億級別訂單分庫分表解決方案

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

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

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

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

本頭條號由餓了麼,螞蟻,阿里等同事業餘時間組成,歡迎加公眾號:jiagoushizhidian


分享到:


相關文章: