分庫(kù)分表需要考慮的問(wèn)題及方案
分庫(kù)分表的基本思想就是把一個(gè)數(shù)據(jù)庫(kù)切分成多個(gè)部分放到不同的數(shù)據(jù)庫(kù),用來(lái)緩解單一數(shù)據(jù)庫(kù)的性能問(wèn)題。即,有兩種拆分方式,第一種拆分方式是把表進(jìn)行拆分,把表放到多個(gè)server上,用來(lái)實(shí)現(xiàn)基本的拆分。第二種拆分方式是在表的數(shù)據(jù)量很大的時(shí)候,按照某種ID順序,切分到多個(gè)數(shù)據(jù)庫(kù)上。這兩種切分方式被稱為水平切分和垂直切分。
常用中間件
這里常用的中間件有以下幾種。
簡(jiǎn)單易用的
當(dāng)當(dāng)網(wǎng) ?sharding-jdbc 蘑菇街:Tsharding
強(qiáng)悍重量級(jí)中間件
sharding TDDL Smart Client Atlas alibaba.cobar MyCat
需要解決的問(wèn)題
事物問(wèn)題
解決事物問(wèn)題,有兩種可行的方案,這里使用分布式事物,或者通過(guò)應(yīng)用程序與數(shù)據(jù)庫(kù)共同控制實(shí)現(xiàn)事物。做一個(gè)簡(jiǎn)單的對(duì)比
方案一:使用分布式事物
優(yōu)點(diǎn):交給數(shù)據(jù)庫(kù)管理,簡(jiǎn)單有效。缺點(diǎn):性能代價(jià)相當(dāng)高。
方案二:由應(yīng)用程序和數(shù)據(jù)庫(kù)共同控制
原理:把一個(gè)跨多個(gè)數(shù)據(jù)庫(kù)的分布式事物分拆成多個(gè)僅處于單個(gè)數(shù)據(jù)庫(kù)上的小事物,通過(guò)應(yīng)用程序來(lái)控制各個(gè)小事物。優(yōu)點(diǎn):性能較高。缺點(diǎn):需要應(yīng)用程序在事物上做控制,
跨節(jié)點(diǎn)join的問(wèn)題
只要是進(jìn)行切分,跨節(jié)點(diǎn)的join就會(huì)有此問(wèn)題。一般做法是分兩次查詢實(shí)現(xiàn)。第一次查詢獲得id,第二次再次查詢獲得第二次的id。
跨節(jié)點(diǎn)的count,order by, group by 以及聚合函數(shù)。
這是一類問(wèn)題,解決辦法就是在分節(jié)點(diǎn)上獲取到數(shù)據(jù),然后在應(yīng)用程序端進(jìn)行合并。
ID 問(wèn)題
一旦數(shù)據(jù)庫(kù)被切分到多個(gè)物理結(jié)點(diǎn)上,此時(shí)需要以下的方式作為數(shù)據(jù)庫(kù)主鍵生成方式。
UUID
這是作為主鍵的最簡(jiǎn)單的方案,索引建立不方便,以及性能不方便。
維護(hù)數(shù)據(jù)庫(kù)的Sequence表
在數(shù)據(jù)庫(kù)中建立一個(gè)相關(guān)的表,表的結(jié)構(gòu)如下
CREATE TABLE `SEQUENCE` (
`table_name` varchar(18) NOT NULL,
`nextid` bigint(20) NOT NULL,
PRIMARY KEY (`table_name`)
) ENGINE=InnoDB
通過(guò)使用Twitter的Snowflake算法
這里使用推特的UUID算法,進(jìn)行生成。
10---0000000000 0000000000 0000000000 0000000000 0 --- 00000 ---00000 ---000000000000 在上面的字符串中,第一位為未使用(實(shí)際上也可作為long的符號(hào)位),接下來(lái)的41位為毫秒級(jí)時(shí)間,然后5位datacenter標(biāo)識(shí)位,5位機(jī)器ID(并不算標(biāo)識(shí)符,實(shí)際是為線程標(biāo)識(shí)),然后12位該毫秒內(nèi)的當(dāng)前毫秒內(nèi)的計(jì)數(shù),加起來(lái)剛好64位,為一個(gè)Long型。
這樣的好處是,整體上按照時(shí)間自增排序,并且整個(gè)分布式系統(tǒng)內(nèi)不會(huì)產(chǎn)生ID碰撞(由datacenter和機(jī)器ID作區(qū)分),并且效率較高,經(jīng)測(cè)試,snowflake每秒能夠產(chǎn)生26萬(wàn)ID左右,完全滿足需要。
跨分片的排序分頁(yè)
一般來(lái)講,分頁(yè)需要按照指定字段進(jìn)行排序,排序字段就是分片信息。通過(guò)分片規(guī)則可以定位到指定的分片。
上面圖中所描述的只是最簡(jiǎn)單的一種情況(取第一頁(yè)數(shù)據(jù)),看起來(lái)對(duì)性能的影響并不大。但是,如果想取出第10頁(yè)數(shù)據(jù),情況又將變得復(fù)雜很多,如下圖所示:

分庫(kù)方式
分庫(kù)確定以后,如何把記錄分到各自庫(kù)里?一般由兩種方式
根據(jù)數(shù)值范圍確定,id為1-999分到一個(gè)庫(kù),999以后分到另外一個(gè)庫(kù)。 進(jìn)行取模。
分庫(kù)數(shù)量
分庫(kù)數(shù)量和單庫(kù)的處理記錄條數(shù)有關(guān),Mysql單庫(kù)5000萬(wàn)條進(jìn)行分庫(kù)。
路由透明
對(duì)于單庫(kù)訪問(wèn),必如查詢條件指定用戶ID,則該SQL只需要訪問(wèn)特定庫(kù),此時(shí)DAL會(huì)進(jìn)行自動(dòng)的路由。
使用框架還是自主研發(fā)
各有優(yōu)勢(shì),各有短板。綜合考慮。
有道無(wú)術(shù),術(shù)可成;有術(shù)無(wú)道,止于術(shù)
歡迎大家關(guān)注Java之道公眾號(hào)
好文章,我在看??
