MySQL分庫分表(其他關(guān)系型數(shù)據(jù)庫也相似),通常的方案都用主鍵mod分表的數(shù)量,來把數(shù)據(jù)路由到某一個(gè)數(shù)據(jù)庫分片上。例如分了10張表,那么就是ID%10,得到結(jié)果0-9,代表不同的表。
但是當(dāng)數(shù)據(jù)量進(jìn)一步增多的時(shí)候,單庫的數(shù)據(jù)量達(dá)到了一定的級(jí)別之后,那么就需要分更多的表,那么這時(shí)候有哪些處理方案呢?
做數(shù)據(jù)遷移最簡(jiǎn)單暴力,也是最麻煩的一個(gè)方案。
因?yàn)楫?dāng)分表(分庫)數(shù)量增多的時(shí)候,因?yàn)榉制?guī)則的變化,每個(gè)表的數(shù)據(jù)都要被重新分配到多個(gè)新的表;這種方法雖然最直接,但是帶來的問題也非常大:
數(shù)據(jù)遷移時(shí)間會(huì)比較長(zhǎng),需要遷移時(shí)間;
如果業(yè)務(wù)不能停的話(在線遷移),還要解決增量數(shù)據(jù)和歷史數(shù)據(jù)一致性的問題;
不做數(shù)據(jù)遷移那么有沒有方法,當(dāng)數(shù)據(jù)增長(zhǎng)到現(xiàn)有分表極限的時(shí)候,加表或者加庫的時(shí)候,可以避免數(shù)據(jù)的遷移呢?說白了,我們需要增加分表算法的復(fù)雜性,讓算法可以兼容增加分表前后的數(shù)據(jù)路由:
先說一個(gè)簡(jiǎn)單的辦法,(為了方便講述,下面就把id當(dāng)做分表字段),如果id是一個(gè)增長(zhǎng)的全局序列,每個(gè)表存500萬的數(shù)據(jù),那么可以id=1-500萬存到table_1,id=500萬零1-1000萬存到table_2,理論上這種方法是可以無限擴(kuò)容的,但是問題也顯而易見,就是每個(gè)階段的數(shù)據(jù)insert會(huì)集中在一個(gè)表/庫上,雖然能避免數(shù)據(jù)遷移的問題,但是數(shù)據(jù)熱點(diǎn)的問題沒有解決。
如果id是一個(gè)增長(zhǎng)的全局序列,當(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),比如Twitter-Snowflake算法,這個(gè)算法是一個(gè)64位的Long值,前42位就是一個(gè)精確到毫秒的時(shí)間戳,那么我們的分庫算法也就可以以某個(gè)時(shí)間點(diǎn)來判斷:
if(id中的時(shí)間<增加分表那一刻的時(shí)間){id%10} else {id%20};我將持續(xù)分享Java開發(fā)、架構(gòu)設(shè)計(jì)、程序員職業(yè)發(fā)展等方面的見解,希望能得到你的關(guān)注。