根據(jù)業(yè)務(wù)初步預(yù)估訂單業(yè)務(wù)量,每天5千萬的數(shù)據(jù)。我們將訂單數(shù)據(jù)劃分為了2大類型:分別為熱數(shù)據(jù)和冷數(shù)據(jù)。
根據(jù)實際業(yè)務(wù)場景,用戶基本不會操作或查詢2個星期以上的數(shù)據(jù),如果這部分?jǐn)?shù)據(jù)存儲在DB中,那么成本會非常高,而且也不方便維護(hù)。另外,如果有特殊情況需要訪問歸檔數(shù)據(jù),可以走離線數(shù)據(jù)查看。
對于這2類數(shù)據(jù),規(guī)劃如下:
熱數(shù)據(jù):使用MySQL進(jìn)行存儲,分庫分表;
冷數(shù)據(jù):ES 或 TiDB或Hive存儲;
MySQL 分庫分表
在業(yè)務(wù)初始階段,為了加快應(yīng)用上線和快速迭代,很多應(yīng)用都采用集中式的架構(gòu)。但是隨著業(yè)務(wù)系統(tǒng)的擴(kuò)大,系統(tǒng)越來越復(fù)雜,越來越難以維護(hù),開發(fā)效率變得越來越低,并且對資源的消耗也變得越來越大,通過硬件提高系統(tǒng)性能的成本會變得更高。
訂單庫也可以根據(jù)不同的業(yè)務(wù)場景,如大客戶訂單、散客訂單等等,進(jìn)行DB拆分。
將不同的業(yè)務(wù)放到不同的庫中,將原來所有壓力由同一個庫中分散到不同的庫中,提升了系統(tǒng)的吞吐量。
在訂單表中,order_id 允許重復(fù),可以將該字段作為sharding key。假設(shè)單個庫需要分配 10 張表可以滿足業(yè)務(wù)需要,可以簡單地取模計算出訂單分配到哪張表。
一旦確定sharding key,就只能根據(jù)sharding key定位到子表進(jìn)而查詢該子表下的數(shù)據(jù);如果確實想根據(jù)user_id 去查詢相關(guān)訂單,那么需要先根據(jù)user_id 查詢映射到的order_id list,然后再根據(jù)order_id list 再查詢。
數(shù)據(jù)庫分表能夠解決單表數(shù)據(jù)量很大的時候數(shù)據(jù)查詢的效率問題,但是無法給數(shù)據(jù)庫的并發(fā)操作帶來效率上的提高,因為分表的實質(zhì)還是在同一個數(shù)據(jù)庫Server上進(jìn)行的操作,很容易受數(shù)據(jù)庫Server IO 性能的限制。
因此, 可以將數(shù)據(jù)進(jìn)行分庫操作,可以解決單臺數(shù)據(jù)庫Server的性能瓶頸。
分庫策略與分表策略的實現(xiàn)很相似,最簡單的都是可以通過取模的方式進(jìn)行路由。
如果order_id 不是整數(shù)類型,可以先hash 在進(jìn)行取模,如 hash(order_id) % DB數(shù)量。
數(shù)據(jù)庫分表可以解決單表海量數(shù)據(jù)的查詢性能問題,分庫可以解決單臺數(shù)據(jù)庫的并發(fā)訪問壓力問題。有時候,我們需要同時考慮這兩個問題,因此,我們既需要對單表進(jìn)行分表操作,還需要進(jìn)行分庫操作,以便同時擴(kuò)展系統(tǒng)的并發(fā)處理能力和提升單表的查詢性能,就是我們使用到的分庫分表。
如果分庫和分表都使用同一個拆分鍵進(jìn)行 Sharding 時,根據(jù)拆分鍵的鍵值按總的分表數(shù)(分庫數(shù)x分表數(shù))取余。
例如,有 2 個分庫,每個分庫 4 張分表,那么 0 庫上保存分表 0~3,1 庫上保存分表 4~7。某個鍵值為 15,15 % (2 * 4) = 7,所以 15 被分到 1 庫的表 7 上。
將訂單請求分為查詢和更新請求,更新請求比較簡單,就是根據(jù)分庫分表規(guī)則寫入db即可。
對于查詢請求,我們需要計算出查詢的是熱數(shù)據(jù)還是冷數(shù)據(jù),根據(jù)查詢的時間范圍計算出查詢的是熱數(shù)據(jù)還是冷數(shù)據(jù)?;蛘邿o法確定熱數(shù)據(jù)、冷數(shù)據(jù),就都走ES 或TiDB。
另外架構(gòu)圖中的冷數(shù)據(jù)指的是近期1年的數(shù)據(jù),如果是查詢一年前的數(shù)據(jù),建議直接離線查hive即可。
圖中有一個定時Job,主要用來定時遷移訂單數(shù)據(jù),需要將冷數(shù)據(jù)分別遷移到ES和hive中。