分庫(kù)分表實(shí)戰(zhàn):新的挑戰(zhàn)—千萬級(jí)數(shù)據(jù)優(yōu)化之垂直拆分
前 言
讀寫分離方案上線后,訂單sql查詢時(shí)間再一次穩(wěn)定在了300ms以下,此時(shí)對(duì)數(shù)據(jù)的增刪改操作會(huì)走主庫(kù),而讀請(qǐng)求會(huì)走從庫(kù),通過讀寫分離大大提升了數(shù)據(jù)讀的處理能力,但遺憾的是沒辦法提升主庫(kù)寫數(shù)據(jù)的能力。
新的挑戰(zhàn)
那么什么時(shí)候主庫(kù)寫數(shù)據(jù)的壓力會(huì)過大呢?其實(shí)我們之前也聊過這個(gè)問題,那就是多個(gè)業(yè)務(wù)共用一個(gè)物理數(shù)據(jù)庫(kù)的,比如商品相關(guān)的表、訂單相關(guān)的表和用戶相關(guān)的表等,所有表都放到了一個(gè)mysql數(shù)據(jù)庫(kù)中,就像這樣:
此時(shí)商品模塊、訂單模塊、用戶模塊都部署在同一臺(tái)物理數(shù)據(jù)庫(kù)上,說白了就是主庫(kù)上,那么此時(shí)這臺(tái)物理數(shù)據(jù)庫(kù)的CPU、內(nèi)存和網(wǎng)絡(luò)的負(fù)載能力,都是商品模塊、訂單模塊、用戶模塊共用的。
這就很尷尬了,由于這3個(gè)模塊是共用同一臺(tái)數(shù)據(jù)庫(kù)的資源,那么就勢(shì)必會(huì)相互影響,比如某一天商品模塊做了一些活動(dòng),尷尬的是商品模塊并沒有做讀寫分離,那么這個(gè)時(shí)候可能商品模塊,會(huì)對(duì)這臺(tái)物理數(shù)據(jù)庫(kù)進(jìn)行大量的讀操作,此時(shí)這臺(tái)物理數(shù)據(jù)庫(kù)的CPU、內(nèi)存和網(wǎng)絡(luò)負(fù)載占用都很高。
而數(shù)據(jù)庫(kù)的資源是有限的,既然商品模塊占用了大量的數(shù)據(jù)庫(kù)資源,那么留給訂單模塊可用的資源就非常少了,這個(gè)時(shí)候就會(huì)導(dǎo)致訂單庫(kù)寫數(shù)據(jù)很慢,寫入一條訂單數(shù)據(jù)突增到了2s,對(duì)于訂單來說,這個(gè)肯定是萬萬不能接受的
那么有沒有破局之道呢?那當(dāng)然是有的,那就是垂直拆分。
怎么做垂直拆分?
垂直拆分其實(shí)分為垂直分庫(kù)和垂直分表,我們這里指的是垂直分庫(kù),說白了就是由一個(gè)數(shù)據(jù)庫(kù)拆分出來多個(gè)數(shù)據(jù)庫(kù),那么具體怎么拆分呢?
其實(shí)可以從數(shù)據(jù)表的維度來拆分,將表做一個(gè)分類,比如之前一個(gè)庫(kù)100張表,現(xiàn)在我分成了10個(gè)mysql數(shù)據(jù)庫(kù),每個(gè)數(shù)據(jù)庫(kù)10張表的數(shù)據(jù),這樣每個(gè)數(shù)據(jù)庫(kù)的壓力就會(huì)很小。
垂直拆分說白了就是將一個(gè)大的系統(tǒng)的多張表,做一個(gè)分類,一般按照模塊來拆分出一個(gè)一個(gè)的數(shù)據(jù)庫(kù),而每個(gè)數(shù)據(jù)庫(kù)中只存放一類數(shù)據(jù)表,每個(gè)數(shù)據(jù)庫(kù)都有一批表,而且都是同一個(gè)模塊的表。
比如一般在外賣系統(tǒng)中,包含商品模塊、訂單模塊、用戶模塊等,垂直拆分就是將每個(gè)模塊的一類表,都分別放到單獨(dú)的庫(kù)中,分而治之,這樣說白了就是分布式系統(tǒng)、微服務(wù)拆分后的效果了:
這樣就可以解決剛才的問題了,因?yàn)楦驹蚴沁@3個(gè)模塊共用了一臺(tái)數(shù)據(jù)庫(kù)的資源,結(jié)果商品模塊占用數(shù)據(jù)庫(kù)服務(wù)器大量資源的時(shí)候,留給訂單模塊的資源自然就少了,所以破局之道就是我們就需要把這3個(gè)模塊的數(shù)據(jù)庫(kù)拆分開,不讓它們共用一臺(tái)物理數(shù)據(jù)庫(kù),而是給每個(gè)業(yè)務(wù)模塊,配備一臺(tái)自己獨(dú)立的物理數(shù)據(jù)庫(kù)服務(wù)器,說白了就是將數(shù)據(jù)庫(kù)進(jìn)行了垂直分庫(kù),由共用一個(gè)大雜燴數(shù)據(jù)庫(kù),拆分為獨(dú)立的商品數(shù)據(jù)庫(kù)、訂單數(shù)據(jù)庫(kù)和用戶數(shù)據(jù)庫(kù)。
不過在實(shí)際的分庫(kù)中,我們可能需要考慮一個(gè)情況,就是有些模塊關(guān)聯(lián)性比較大,可能經(jīng)常需要一起查詢。所以這時(shí)候,我們也可以把強(qiáng)關(guān)聯(lián)的一些模塊的表放在一個(gè)庫(kù),避免跨庫(kù)查詢帶來的效率降低。
好了,此時(shí)由于我們已經(jīng)把不同模塊的表放到了不同的數(shù)據(jù)庫(kù)中,每個(gè)庫(kù)都有自己獨(dú)立的一臺(tái)物理服務(wù)器,那么這臺(tái)物理數(shù)據(jù)庫(kù)的CPU、內(nèi)存和網(wǎng)絡(luò)的負(fù)載能力都是相互隔離的,因此之前資源相互占用的問題也就不存在了。
垂直拆分有哪些好處呢?
垂直拆分是可以帶來很多好處的,比如可以幫我們減輕數(shù)據(jù)庫(kù)的壓力,當(dāng)我們按照模塊分庫(kù)之后,不同模塊的數(shù)據(jù)表,現(xiàn)在已經(jīng)被分到了多個(gè)數(shù)據(jù)庫(kù)中了,每個(gè)數(shù)據(jù)庫(kù)中的數(shù)據(jù),就不會(huì)那么多了,查詢的效率就會(huì)更高了。
另外,單個(gè)數(shù)據(jù)庫(kù)的數(shù)據(jù)量變少了之后,相應(yīng)的CPU、內(nèi)存、網(wǎng)絡(luò)的負(fù)載的壓力,也會(huì)相應(yīng)的降低,整體的查詢效率也會(huì)提高。
垂直拆分后,業(yè)務(wù)會(huì)變的更加清晰,維護(hù)數(shù)據(jù)也會(huì)很方便,因?yàn)橐粋€(gè)庫(kù)拆分成了多個(gè)庫(kù),每個(gè)庫(kù)中的表都是一個(gè)業(yè)務(wù)模塊的,所以一個(gè)庫(kù)中就一個(gè)模塊的業(yè)務(wù),很清晰。
并且,數(shù)據(jù)維護(hù)也是,需要找哪個(gè)模塊的數(shù)據(jù),就到對(duì)應(yīng)庫(kù)中找,不會(huì)像拆分前,多個(gè)模塊的數(shù)據(jù)糅在一起,維護(hù)數(shù)據(jù)也簡(jiǎn)單,因?yàn)槎鄠€(gè)模塊的數(shù)據(jù),解耦了,修改一個(gè)庫(kù)中的數(shù)據(jù),不會(huì)影響其他庫(kù)的數(shù)據(jù)。
而且,系統(tǒng)擴(kuò)展也會(huì)變的更容易一些,現(xiàn)在各個(gè)模塊都拆分出來了,比如訂單模塊,就從外賣系統(tǒng)中,單獨(dú)拆分出來一個(gè)模塊了,這個(gè)訂單模塊的數(shù)據(jù),在一個(gè)數(shù)據(jù)庫(kù)中和其他模塊的數(shù)據(jù),就獨(dú)立了。
如果訂單模塊業(yè)務(wù)要做復(fù)雜了,需要擴(kuò)展了,比如訂單的表結(jié)構(gòu)要設(shè)計(jì)的更復(fù)雜點(diǎn),添加更多的業(yè)務(wù)設(shè)計(jì),對(duì)其它模塊都是透明的,很容易擴(kuò)展;不會(huì)像之前一樣,多個(gè)模塊的多張表,耦合在一個(gè)庫(kù)中,也不好拓展,因?yàn)闀?huì)擔(dān)心影響到其他業(yè)務(wù)。
垂直拆分有什么不足的地方嗎?
好了,說了垂直分庫(kù)的這么多好處,那么它有沒有一些不足的地方呢?答案是肯定的。
首先就是系統(tǒng)會(huì)變的更復(fù)雜,因?yàn)楝F(xiàn)在垂直拆分之后,多個(gè)模塊的表,都分別分到不同的數(shù)據(jù)庫(kù)中了,如果現(xiàn)在有一個(gè)查詢操作,要關(guān)聯(lián)多張表,這個(gè)時(shí)候,就不能簡(jiǎn)單使用join來進(jìn)行關(guān)聯(lián)查詢了。
比如a表在A庫(kù),b表在B庫(kù),這個(gè)時(shí)候就不能簡(jiǎn)單的join連接了,而需要先通過接口的方式,先獲取到a表的數(shù)據(jù),然后再通過接口獲取b表的數(shù)據(jù),這樣操作就變復(fù)雜了。
另外,事務(wù)的處理也會(huì)變得更加的麻煩,之前要處理事務(wù)的話,在一個(gè)數(shù)據(jù)庫(kù)中處理即可,出現(xiàn)問題直接回滾事務(wù)就行了。
但是現(xiàn)在要操作的數(shù)據(jù),可能是分布在多個(gè)數(shù)據(jù)庫(kù)中的,如果操作過程中的某個(gè)環(huán)節(jié)出問題了,就不能簡(jiǎn)單的回滾事務(wù)了,因?yàn)楝F(xiàn)在是橫跨多個(gè)數(shù)據(jù)庫(kù)的事務(wù),這個(gè)時(shí)候就要用到分布式事務(wù)的解決方案了,就更復(fù)雜了。
而且,單庫(kù)的性能也會(huì)很快的遇到瓶頸,雖然現(xiàn)在一個(gè)大的系統(tǒng)的多張表,按照不同??烨谐隽硕鄠€(gè)數(shù)據(jù)庫(kù),每個(gè)庫(kù)有相應(yīng)模塊的表,可能某一個(gè)模塊的數(shù)據(jù)量會(huì)特別大,比如訂單模塊,相比于其他模塊而言,數(shù)據(jù)量會(huì)非常大。
并且這里通常是單表數(shù)據(jù)量過大,比如訂單表單表可能已經(jīng)6000W數(shù)據(jù)了,這個(gè)時(shí)候訂單表的讀寫效率已經(jīng)開始明顯降低了。
像這種單表數(shù)據(jù)量過大的問題,垂直分庫(kù)是解決不了的,所以這個(gè)時(shí)候就需要對(duì)訂單表進(jìn)行進(jìn)一步的拆分,也就是水平拆分。
由于我們實(shí)戰(zhàn)是以外賣訂單業(yè)務(wù)為主,所以本身就只有一個(gè)訂單數(shù)據(jù)庫(kù),其實(shí)天然就已經(jīng)做了垂直分庫(kù),所以這個(gè)垂直分庫(kù)我們就不進(jìn)行實(shí)戰(zhàn)了,后邊的水平分庫(kù)分表是我們的重頭戲,到時(shí)候會(huì)帶著大家一起設(shè)計(jì)水平分庫(kù)分表的落地方案和數(shù)據(jù)遷移方案的,大家敬請(qǐng)期待!