數(shù)據(jù)庫在做了分庫分表之后,關于ID主鍵,我認為需要考慮這幾點:
生成算法當我們的數(shù)據(jù)庫是單臺的時候,是不用太操心主鍵的生成,但是當數(shù)據(jù)庫進行了分庫分表之后,那么主鍵的生成就需要注意了,至少不能使用數(shù)據(jù)庫內(nèi)部的自增長序列了,通常要引入分布式唯一標識碼的生成算法。
利用數(shù)據(jù)庫生成:先說最笨的方法,利用數(shù)據(jù)庫的自增長序列生成,數(shù)據(jù)庫內(nèi)唯一,有人會說,剛說完不能用數(shù)據(jù)庫的自增長序列,這么快就要被打臉了么?其實這個的意思是,先利用(額外)的一臺數(shù)據(jù)庫,通過其自增長序列得到主鍵,然后作為分庫分表的主鍵;
利用Redis/MongoDB/zookeeper生成:Redis的單線程的,利用incr和increby;MongoDB的ObjectId;ZK通過znode數(shù)據(jù)版本;都可以生成全局的唯一標識碼;
UUID:生成唯一標識碼最常用的算法之一;
Snowflake:Twitter開源,基于zk,41位時間戳(毫秒數(shù))+10位機器的ID+12位毫秒內(nèi)的流水號+1位符號位(永遠是0);
UidGenerator:百度開源,基于snowflake算法;
Leaf:美團開源,能保證全局唯一性、高可用、趨勢遞增(不太安全,比如泄露公司訂單數(shù)量)、單調(diào)遞增等。
擴容會比較麻煩分庫分表通常的方案都用主鍵mod分表的數(shù)量,來把數(shù)據(jù)路由到某一個數(shù)據(jù)庫分片上。例如分了10張表,那么就是ID%10,得到結(jié)果0-9,代表不同的表;但是當數(shù)據(jù)量進一步增多的時候,單庫的數(shù)據(jù)量達到了一定的級別之后,那么就需要分更多的表,那么這時候有哪些處理方案呢?
做數(shù)據(jù)遷移:最簡單暴力,也是最麻煩的一個方案;因為當分表(分庫)數(shù)量增多的時候,因為分片規(guī)則的變化,每個表的數(shù)據(jù)都要被重新分配到多個新的表;
如果id是一個增長的全局序列,當前有十張表,那么分表的算法為:id%10,根據(jù)0-9路由到10個表中;當表擴到20張的時候,擴容那一刻取max_id,那么未來分庫的算法也就變成了:
if(id<max_id){id%10} else {id%20};有些分表的算法本身就帶時間戳,可以基于id中的時間戳來實現(xiàn),比如Snowflake算法(見上文),這個算法是一個64位的Long值,前42位就是一個精確到毫秒的時間戳,那么我們的分庫算法也就可以以某個時間點來判斷:
if(id中的時間<增加分表那一刻的時間){id%10} else {id%20};我將持續(xù)分享Java開發(fā)、架構(gòu)設計、程序員職業(yè)發(fā)展等方面的見解,希望能得到你的關注。