{eval=Array;=+count(Array);}
我從分庫分表存在的問題和怎么做來回答一下這個(gè)問題。。
一,分庫分表的ID主鍵不能依賴于數(shù)據(jù)庫的自增,因?yàn)槎鄮熘袝?huì)重復(fù)!
通常使用外接的數(shù)據(jù)組件獲取全局唯一的ID:比如加強(qiáng)型UUID(根據(jù)Ip,時(shí)間戳等得到)和使用Redis(RedisAtomicLong)和zookeeper的API獲取,Twitter的雪花算法等等!
二,分庫分表之后的連接查詢比較困難!
問題沒法避免,通常拆分SQL,使用多次查詢,用查到的結(jié)果再分別查別的結(jié)果!
三,分布式事務(wù)的數(shù)據(jù)一致性很難保證!
可以使用TCC編程模型保證兩處的事務(wù)都能正確提交,但是這種方式對代碼的侵入比較重!也可以使用基于消息的數(shù)據(jù)一致性保證!
四,多數(shù)據(jù)的排序,分組,統(tǒng)計(jì)會(huì)比較困難!
1,用多線程,對多個(gè)節(jié)點(diǎn)分別查詢,然后匯總!
2,也可以提前冗余查詢表,將所有的經(jīng)常查詢的重點(diǎn)數(shù)據(jù)提前統(tǒng)一到個(gè)庫表里!
分庫分表涉及到的知識點(diǎn)比較多,建議使用專門的分庫分表組件!本人有mycat使用經(jīng)驗(yàn),如果您有相關(guān)問題,歡迎前來探討!
數(shù)據(jù)庫在做了分庫分表之后,關(guān)于ID主鍵,我認(rèn)為需要考慮這幾點(diǎn):
當(dāng)我們的數(shù)據(jù)庫是單臺的時(shí)候,是不用太操心主鍵的生成,但是當(dāng)數(shù)據(jù)庫進(jìn)行了分庫分表之后,那么主鍵的生成就需要注意了,至少不能使用數(shù)據(jù)庫內(nèi)部的自增長序列了,通常要引入分布式唯一標(biāo)識碼的生成算法。
利用數(shù)據(jù)庫生成:先說最笨的方法,利用數(shù)據(jù)庫的自增長序列生成,數(shù)據(jù)庫內(nèi)唯一,有人會(huì)說,剛說完不能用數(shù)據(jù)庫的自增長序列,這么快就要被打臉了么?其實(shí)這個(gè)的意思是,先利用(額外)的一臺數(shù)據(jù)庫,通過其自增長序列得到主鍵,然后作為分庫分表的主鍵;
利用Redis/MongoDB/zookeeper生成:Redis的單線程的,利用incr和increby;MongoDB的ObjectId;ZK通過znode數(shù)據(jù)版本;都可以生成全局的唯一標(biāo)識碼;
UUID:生成唯一標(biāo)識碼最常用的算法之一;
Snowflake:Twitter開源,基于zk,41位時(shí)間戳(毫秒數(shù))+10位機(jī)器的ID+12位毫秒內(nèi)的流水號+1位符號位(永遠(yuǎn)是0);
UidGenerator:百度開源,基于snowflake算法;
Leaf:美團(tuán)開源,能保證全局唯一性、高可用、趨勢遞增(不太安全,比如泄露公司訂單數(shù)量)、單調(diào)遞增等。
分庫分表通常的方案都用主鍵mod分表的數(shù)量,來把數(shù)據(jù)路由到某一個(gè)數(shù)據(jù)庫分片上。例如分了10張表,那么就是ID%10,得到結(jié)果0-9,代表不同的表;但是當(dāng)數(shù)據(jù)量進(jìn)一步增多的時(shí)候,單庫的數(shù)據(jù)量達(dá)到了一定的級別之后,那么就需要分更多的表,那么這時(shí)候有哪些處理方案呢?
做數(shù)據(jù)遷移:最簡單暴力,也是最麻煩的一個(gè)方案;因?yàn)楫?dāng)分表(分庫)數(shù)量增多的時(shí)候,因?yàn)榉制?guī)則的變化,每個(gè)表的數(shù)據(jù)都要被重新分配到多個(gè)新的表;
如果id是一個(gè)增長的全局序列,當(dāng)前有十張表,那么分表的算法為:id%10,根據(jù)0-9路由到10個(gè)表中;當(dāng)表擴(kuò)到20張的時(shí)候,擴(kuò)容那一刻取max_id,那么未來分庫的算法也就變成了:
if(id<max_id){id%10} else {id%20};
有些分表的算法本身就帶時(shí)間戳,可以基于id中的時(shí)間戳來實(shí)現(xiàn),比如Snowflake算法(見上文),這個(gè)算法是一個(gè)64位的Long值,前42位就是一個(gè)精確到毫秒的時(shí)間戳,那么我們的分庫算法也就可以以某個(gè)時(shí)間點(diǎn)來判斷:
if(id中的時(shí)間<增加分表那一刻的時(shí)間){id%10} else {id%20};
數(shù)據(jù)量達(dá)到查詢瓶頸的時(shí)候,需要做一些拆分或索引優(yōu)化處理。
對于使用id主鍵來說,分庫分表都要做一些特別的設(shè)計(jì),有以下幾個(gè)方案。
1、id區(qū)間提前規(guī)劃好,每個(gè)庫分配好整數(shù)區(qū)間,每個(gè)庫中的每個(gè)表也要規(guī)劃號,數(shù)字那么大,總有區(qū)間能夠容納下增長的數(shù)字。
2、id采用32位全局uuid保證唯一
3、通過雪花算法,得到分布式環(huán)境下全局唯一的id
4、采用納秒級時(shí)間戳+隨機(jī)數(shù)+重試機(jī)制保證數(shù)據(jù)唯一。
由于數(shù)據(jù)庫的索引大部分采用B+數(shù)數(shù)據(jù)結(jié)構(gòu)來存儲,主鍵的線性遞增對數(shù)據(jù)的插入(B+樹的拆分和合并)和查詢性能有優(yōu)勢,所以建議采用能保證主鍵遞增的方案。
全局id生成算法 snowklake算法 用long型64位表示 1位表示符號位正整數(shù) 41位表示時(shí)間戳 10位表示機(jī)器碼 12位表示順序位
為什么要分物理表呢? 分區(qū)的底層同樣是物理分表但上層MySQL已做好一切展現(xiàn)給我們的是一個(gè)總表,不同的數(shù)據(jù)放到不同分區(qū),CURD甚至索引完全就是當(dāng)成一個(gè)表來操作,其實(shí)展現(xiàn)給用戶的就是一張表,但底層分成了若干個(gè)區(qū)
看你怎么分,但無論怎么分都要保留或新建主建來關(guān)聯(lián)數(shù)據(jù),數(shù)據(jù)關(guān)聯(lián)不起來,就廢了。
0
回答0
回答1
回答0
回答0
回答0
回答0
回答0
回答0
回答0
回答