數(shù)據(jù)庫(kù)的分庫(kù)分表是什么?
阿粉相信,現(xiàn)在很多的做開發(fā)的都喜歡研究一些新的技術(shù),但是能不能把數(shù)據(jù)都實(shí)際應(yīng)用到公司的環(huán)境中,這個(gè)就不好說(shuō)了,畢竟有些東西用上了,一旦出現(xiàn)問(wèn)題了,那么就會(huì)導(dǎo)致一連串的生產(chǎn)事故的發(fā)生。今天阿粉就來(lái)學(xué)習(xí)一下這個(gè)Sharding,也就是分庫(kù)分表實(shí)戰(zhàn),接下來(lái)我們來(lái)學(xué)習(xí)一下什么是分庫(kù)分表,什么是Sharding。
什么是分庫(kù)分表
分庫(kù),顯而易見,就是一個(gè)數(shù)據(jù)庫(kù)分成多個(gè)數(shù)據(jù)庫(kù),部署到不同機(jī)器。
分表,就是一個(gè)數(shù)據(jù)庫(kù)表分成多個(gè)表。
那么為什么需要分庫(kù)分表呢?
為什么需要分庫(kù)分表?
首先我們要明確一個(gè)問(wèn)題,單一的數(shù)據(jù)庫(kù)是否能夠滿足公司目前的線上業(yè)務(wù)需求,比如,我們的用戶表,可能有幾千萬(wàn),甚至上億的數(shù)據(jù),阿粉只是說(shuō)可能,如果有這么多用戶,那必然是大公司了,那么這個(gè)時(shí)候,如果你不分表也不分庫(kù)的話,那么數(shù)據(jù)了上來(lái)的時(shí)候,稍微一個(gè)不注意,MySQL單機(jī)磁盤容量會(huì)撐爆,但是如果拆成多個(gè)數(shù)據(jù)庫(kù),磁盤使用率大大降低。
這樣就把磁盤使用率降低,這是通過(guò)硬件的形式解決問(wèn)題,就像阿粉所有,如果你的數(shù)據(jù)量是巨大的,這時(shí)候,SQL 如果沒(méi)有命中索引,那么就會(huì)導(dǎo)致一個(gè)情況,查這個(gè)表的SQL語(yǔ)句直接把數(shù)據(jù)庫(kù)給干崩了。
即使SQL命中了索引,如果表的數(shù)據(jù)量 超過(guò)一千萬(wàn)的話, 查詢也是會(huì)明顯變慢的。這是因?yàn)樗饕话闶荁+樹結(jié)構(gòu),數(shù)據(jù)千萬(wàn)級(jí)別的話,B+樹的高度會(huì)增高,查詢自然就變慢了,當(dāng)然,這是題外話了。
那么我們接下來(lái)就得說(shuō)說(shuō)如何進(jìn)行分庫(kù)和分表的操作了,今天阿粉就講一下這個(gè)如何進(jìn)行進(jìn)行分庫(kù)分表。
分庫(kù)分表方案
分庫(kù)分表方案,不外乎就兩種,一種是垂直切分,一種是水平切分。
但是總有做開發(fā)的小伙伴不知道這垂直切分和水平切分到底是什么樣的,為什么垂直切分,為什么水平切分,什么時(shí)候應(yīng)該選擇垂直切分,什么時(shí)候應(yīng)該選擇水平切分。
有人是這么說(shuō)的,垂直切分是根據(jù)業(yè)務(wù)來(lái)拆分?jǐn)?shù)據(jù)庫(kù),同一類業(yè)務(wù)的數(shù)據(jù)表拆分到一個(gè)獨(dú)立的數(shù)據(jù)庫(kù),另一類的數(shù)據(jù)表拆分到其他數(shù)據(jù)庫(kù)。
有些人不理解這個(gè),實(shí)際上垂直切分也是有劃分的,上面描述的是垂直切分?jǐn)?shù)據(jù)庫(kù),可能容易讓很多人不太理解,但是如果是垂直切分表,那么肯定百分之90的人都能理解。
我們又一張Order表,表中有諸多記錄,比如我們?cè)O(shè)計(jì)這么一張簡(jiǎn)單的表。
字段有如下。
id | order_id | order_date | order_type | order_state |
1 | cd96cff0356e483caae6b2ff4e878fd6 | 2022-06-11 13:57:11 | 支付寶 | 1 |
2 | e2496f9e22ce4391806b18480440526a | 2022-06-12 14:22:33 | 微信 | 2 |
3 | 9e7ab5a1915c4570a9eaaaa3c01f79c1 | 2022-06-12 15:21:44 | 現(xiàn)金 | 2 |
以上是我們的簡(jiǎn)化版Order表,如果我們想要垂直切分,那么應(yīng)該怎么處理?
直接拆分成2個(gè)表,這時(shí)候就直接就一份為2 ,咔的一下拆分成兩個(gè)表?
Order1
id | order_id | order_date |
1 | cd96cff0356e483caae6b2ff4e878fd6 | 2022-06-11 13:57:11 |
2 | e2496f9e22ce4391806b18480440526a | 2022-06-12 14:22:33 |
3 | 9e7ab5a1915c4570a9eaaaa3c01f79c1 | 2022-06-12 15:21:44 |
Order2
id | order_type | order_state |
1 | 支付寶 | 1 |
2 | 微信 | 2 |
3 | 現(xiàn)金 | 2 |
這時(shí)候我們的主鍵ID保持的時(shí)一致的,而這個(gè)操作,就是垂直拆分,分表的操作。
既然我們說(shuō)了垂直拆分,那么必然就有水平拆分。
什么是水平拆分呢?
實(shí)際上水平拆分的話,那真的是只有一句話。
按照數(shù)據(jù)來(lái)拆分
水平拆分?jǐn)?shù)據(jù)庫(kù):將一張表的數(shù)據(jù) ( 按照數(shù)據(jù)行) 分到多個(gè)不同的數(shù)據(jù)庫(kù).每個(gè)庫(kù)的表結(jié)構(gòu)相同. 每個(gè) 庫(kù)都只有這張表的部分?jǐn)?shù)據(jù),當(dāng)單表的數(shù)據(jù)量過(guò)大,如果繼續(xù)使用水平分庫(kù), 那么數(shù)據(jù)庫(kù)的實(shí)例 就會(huì)不斷增加,不利于系統(tǒng)的運(yùn)維. 這時(shí)候就要采用水平分表。
水平拆分分表: 將一張表的數(shù)據(jù) ( 按照數(shù)據(jù)行) , 分配到同一個(gè)數(shù)據(jù)庫(kù)的多張表中,每個(gè)表都只有一部 分?jǐn)?shù)據(jù)。
我們來(lái)看看Order表進(jìn)行水平拆分的話,是什么樣子的。
Order1
id | order_id | order_date | order_type | order_state |
1 | cd96cff0356e483caae6b2ff4e878fd6 | 2022-06-11 13:57:11 | 支付寶 | 1 |
2 | e2496f9e22ce4391806b18480440526a | 2022-06-12 14:22:33 | 微信 | 2 |
Order2
id | order_id | order_date | order_type | order_state |
3 | 9e7ab5a1915c4570a9eaaaa3c01f79c1 | 2022-06-12 15:21:44 | 現(xiàn)金 | 2 |
實(shí)際上就是水平的把表數(shù)據(jù)給分成了2份,這么看起來(lái)是不是就很好理解了。
分庫(kù)分表帶來(lái)的問(wèn)題
事務(wù)問(wèn)題首先,分庫(kù)分表最大的隱患就是,事務(wù)的一致性, 當(dāng)我們需要更新的內(nèi)容同時(shí)分布在不同的庫(kù)時(shí),不可避免的會(huì)產(chǎn)生跨庫(kù)的事務(wù)問(wèn)題。原來(lái)在一個(gè)數(shù)據(jù)庫(kù)操作,本地事務(wù)就可以進(jìn)行控制,分庫(kù)之后 一個(gè)請(qǐng)求可能要訪問(wèn)多個(gè)數(shù)據(jù)庫(kù),如何保證事務(wù)的一致性,目前還沒(méi)有簡(jiǎn)單的解決方案。
無(wú)法連表的問(wèn)題
還有一個(gè)就是,沒(méi)有辦法進(jìn)行連表查詢了,因?yàn)椋? 原來(lái)在一個(gè)庫(kù)中的一些表,被分散到多個(gè)庫(kù),并且這些數(shù)據(jù)庫(kù)可能還不在一臺(tái)服務(wù)器,無(wú)法關(guān)聯(lián)查詢。所以相對(duì)應(yīng)的業(yè)務(wù)代碼可能就比較多了。
分頁(yè)問(wèn)題
分庫(kù)并行查詢時(shí),如果用到了分頁(yè) 每個(gè)庫(kù)返回的結(jié)果集本身是無(wú)序的, 只有將多個(gè)庫(kù)中的數(shù)據(jù)先查出來(lái),然后再根據(jù)排序字段在內(nèi)存中進(jìn)行排序,如果查詢結(jié)果過(guò)大也是十分消耗資源的。
阿粉之前用過(guò)一次分頁(yè),直接能把線上CPU瞬間會(huì)有一個(gè)頂峰值。所以,慎重呀。
分庫(kù)分表的技術(shù)
目前比較流行的就兩種,一種是MyCat,另外一種則是Sharding-jdbc,都是可以進(jìn)行分庫(kù)的。
MyCat是一個(gè)數(shù)據(jù)庫(kù)中間件,Sharding-jdbc是以 jar 包提供服務(wù)的jdbc框架。
如果要是讓阿粉選擇,那么阿粉絕對(duì)會(huì)選擇最方便快捷的,也就是jar包的形式來(lái)操作。
Mycat和Sharding-jdbc 實(shí)現(xiàn)原理也是不同。
Mycat的原理中最重要的一個(gè)動(dòng)詞是“攔截”,它攔截了用戶發(fā)送過(guò)來(lái)的SQL語(yǔ)句,首先對(duì)SQL語(yǔ)句做了一些特定的分析:如分庫(kù)分表分析、路由分析、讀寫分離分析、緩存分析等,然后將此SQL發(fā)往后端的真實(shí)數(shù)據(jù)庫(kù),并將返回的結(jié)果做適當(dāng)?shù)奶幚?,最終再返回給用戶。
而Sharding-JDBC的原理是接受到一條SQL語(yǔ)句時(shí),會(huì)陸續(xù)執(zhí)行SQL解析 => 查詢優(yōu)化 => SQL路由 => SQL改寫 => SQL執(zhí)行 => 結(jié)果歸并 ,最終返回執(zhí)行結(jié)果。