分庫分表設(shè)計(jì)
1、什么是分庫分表
? ? ? ? 數(shù)據(jù)拆分是對(duì)數(shù)據(jù)進(jìn)行分而治之的通用概念
?垂直拆分:根據(jù)業(yè)務(wù)維度,將原本一個(gè)庫(表)拆分為多個(gè)庫(表),每個(gè)庫(表)與原有的結(jié)構(gòu)不同。例如將用戶表和訂單表分別存于兩個(gè)不同的數(shù)據(jù)庫中,或者將用戶表中的一些信息拆分存于不同的表中。
? ?優(yōu)點(diǎn):
拆分后業(yè)務(wù)清晰,拆分規(guī)則明確
系統(tǒng)之間進(jìn)行整合或擴(kuò)展容易
按照成本、應(yīng)用等級(jí)、應(yīng)用的類型等將表放到不同的機(jī)器上,便于管理
便于實(shí)現(xiàn)動(dòng)靜分離、冷熱分離的數(shù)據(jù)庫表設(shè)計(jì)模式。(冷數(shù)據(jù)查詢多,適合MyISAM引擎,熱數(shù)據(jù)更新頻繁,適合InnoDB)
數(shù)據(jù)維護(hù)簡(jiǎn)單
? ? 缺點(diǎn) :
部分業(yè)務(wù)表無法關(guān)聯(lián)(join),只能通過接口方式解決,提高系統(tǒng)的復(fù)雜度
受每種業(yè)務(wù)的不同限制,存在單庫性能瓶頸,不易進(jìn)行數(shù)據(jù)擴(kuò)展和提升性能
事務(wù)處理復(fù)雜
水平拆分:根據(jù)分片(sharding)算法,將一個(gè)庫(表)拆分為多個(gè)庫(表),每個(gè)庫(表)保留原有的結(jié)構(gòu)。例如將用戶表id為0-1000的數(shù)據(jù)存于數(shù)據(jù)庫A中,1001-2000的數(shù)據(jù)存于數(shù)據(jù)庫B中。又或者是id為0-1000的存于數(shù)據(jù)庫A中的table1,1001-2000的存于table2中。
? ? 方法:1、按照哈希切片? 2、按照時(shí)間切片
? ? 優(yōu)點(diǎn):
單庫單表的數(shù)據(jù)保持在一定量級(jí),有助于性能 提高
切分的表結(jié)構(gòu)相同,應(yīng)用層改造較少,只需要增加路由規(guī)則即可(路由:針對(duì)輸入的請(qǐng)求,通過分庫分表規(guī)則找到對(duì)應(yīng)的表和庫的過程)
提高了系統(tǒng)穩(wěn)定性和負(fù)載能力
? ? 缺點(diǎn):
切分后數(shù)據(jù)是分散的,很難利用數(shù)據(jù)庫的join操作,跨庫的join性能差
拆分規(guī)則難以抽象
分片事物的一致性難以解決
數(shù)據(jù)擴(kuò)容難度和維護(hù)量極大
1.1、使用階段:?jiǎn)伪韱螏?、單庫多表、多庫多?/p>
2、什么情況下需要分庫分表
2.1、如果數(shù)據(jù)庫中表的數(shù)據(jù)量達(dá)到一定的量級(jí),則需要進(jìn)行分表,分解單表的大量數(shù)據(jù)量對(duì)索引查詢帶來的壓力,并方便對(duì)索引和表結(jié)構(gòu)的變更
2.2、數(shù)據(jù)庫的吞吐量達(dá)到了瓶頸,就需要增加數(shù)據(jù)庫實(shí)例。
2.3、希望再擴(kuò)容時(shí)對(duì)應(yīng)用層的配置改變最少,就需要再每個(gè)數(shù)據(jù)庫實(shí)例中預(yù)留足夠的數(shù)據(jù)庫數(shù)量
3、分庫分表解決方案
在應(yīng)用層直接實(shí)現(xiàn):直接在應(yīng)用層讀取并解析分片規(guī)則,根據(jù)分片規(guī)則實(shí)現(xiàn)切分的路由邏輯,從應(yīng)用層直接決定每次操作應(yīng)該使用那個(gè)數(shù)據(jù)庫實(shí)例、數(shù)據(jù)庫及哪個(gè)數(shù)據(jù)庫的表。

通過定制JDBC協(xié)議實(shí)現(xiàn):針對(duì)業(yè)務(wù)邏輯層提供與JDBC一致的接口,分庫分表在JDBC內(nèi)部實(shí)現(xiàn),對(duì)業(yè)務(wù)層保持透明。(Sharding JDBC采用此方案)

通過定制ORM框架實(shí)現(xiàn):把分片規(guī)則實(shí)現(xiàn)到ORM框架中或者通過ORM框架支持的擴(kuò)展機(jī)制來完成分庫分表的邏輯。如在MyBatis配置文件SQL中增加表索引的參數(shù)來實(shí)現(xiàn)分片。

代理分片:在應(yīng)用層和數(shù)據(jù)庫層增加一層代理層,把分片的路由規(guī)則配置在代理層,代理層對(duì)外提供與JDBC兼容的接口給應(yīng)用層。(Cobar和MyCat等)

4、分片后的事務(wù)處理機(jī)制
4.1、分布式事務(wù)
? ? ? ?解決方法:
兩階段提交協(xié)議:將分布式事務(wù)分為兩個(gè)階段,一個(gè)是準(zhǔn)備階段,一個(gè)是提交階段,兩個(gè)階段都是由事務(wù)管理器發(fā)起
最大努力保證模式:在更新多個(gè)資源的時(shí)候,將多個(gè)資源的提交盡量延后到最后一刻處理,這樣的話如果過程出現(xiàn)問題,則所有的資源更新都可以回滾
事務(wù)補(bǔ)償機(jī)制:對(duì)于跨庫的多個(gè)操作,可通過補(bǔ)償和重試,使其在一定的時(shí)間窗口內(nèi)完成操作,這樣就可以實(shí)現(xiàn)事務(wù)最終一致性
4.2、事務(wù)路由
自動(dòng)提交事務(wù)路由:依賴JDBC數(shù)據(jù)源的自動(dòng)提交事務(wù)特性,對(duì)任何數(shù)據(jù)庫進(jìn)行更新操作后會(huì)自動(dòng)提交事務(wù)
可編程事務(wù)路由:在分庫分表中,在需要開啟事務(wù)的方法中,需要?jiǎng)討B(tài)的確定開啟哪個(gè)數(shù)據(jù)庫實(shí)例的事務(wù)。
聲明式事務(wù):在實(shí)現(xiàn)的服務(wù)方法上直接聲明事務(wù)的處理注解
5、讀寫分離
當(dāng)讀操作壓力很大時(shí),可以考慮添加從庫機(jī)器來分解大量讀操作帶來的壓力,但是當(dāng)從庫機(jī)器達(dá)到一定的數(shù)量時(shí),就需要考慮分庫來緩解壓力
當(dāng)寫操作壓力很大時(shí),就必須進(jìn)行分庫操作了
當(dāng)由于服務(wù)器性能不一時(shí),可以通過程序控制每臺(tái)機(jī)器讀寫的比重來達(dá)到負(fù)載均衡,這需要更加復(fù)雜的讀寫分離的路由規(guī)則
6、分庫分表引起的問題
6.1、擴(kuò)容與遷移
解決方法:
按照新舊分片規(guī)則,對(duì)新舊數(shù)據(jù)庫進(jìn)行雙寫
將雙寫前按照舊分片規(guī)則寫入的歷史數(shù)據(jù),根據(jù)新分片規(guī)則遷移寫入新的數(shù)據(jù)庫
將按照舊分片規(guī)則的查詢改為新分片規(guī)則查詢
將雙寫數(shù)據(jù)庫邏輯從代碼中下線,只按照新的分片規(guī)則寫入數(shù)據(jù)
刪除按照舊分片規(guī)則寫入的歷史數(shù)據(jù)
6.2、分庫分表維度導(dǎo)致查詢問題
解決方法:
在多個(gè)分片表查詢后合并數(shù)據(jù)集,這種方式的效率低
記錄兩份數(shù)據(jù),一份按照買家維度分表,一份按照商品維度分表(電商系統(tǒng)涉及的查詢)
通過搜索引擎解決,但是如果實(shí)時(shí)性要求很高,就需要實(shí)現(xiàn)實(shí)時(shí)搜索
6.3、跨庫事務(wù)難以實(shí)現(xiàn)
? ? ?盡量避免在一個(gè)事務(wù)中同時(shí)修改db0和db1的表
6.4、同組數(shù)據(jù)跨庫問題
? ? ?盡量把同一組數(shù)據(jù)放到同一臺(tái)服務(wù)器上,不但在某些場(chǎng)景下可以利用本地事務(wù)的強(qiáng)一致性,還可以使這組數(shù)據(jù)自治。