-
1 # 此生唯一
-
2 # 會點程式碼的大叔
資料庫在做了分庫分表之後,關於ID主鍵,我認為需要考慮這幾點:
生成演算法當我們的資料庫是單臺的時候,是不用太操心主鍵的生成,但是當資料庫進行了分庫分表之後,那麼主鍵的生成就需要注意了,至少不能使用資料庫內部的自增長序列了,通常要引入分散式唯一標識碼的生成演算法。
利用資料庫生成:先說最笨的方法,利用資料庫的自增長序列生成,資料庫內唯一,有人會說,剛說完不能用資料庫的自增長序列,這麼快就要被打臉了麼?其實這個的意思是,先利用(額外)的一臺資料庫,透過其自增長序列得到主鍵,然後作為分庫分表的主鍵;
利用Redis/MongoDB/zookeeper生成:Redis的單執行緒的,利用incr和increby;MongoDB的ObjectId;ZK透過znode資料版本;都可以生成全域性的唯一標識碼;
UUID:生成唯一標識碼最常用的演算法之一;
Snowflake:Twitter開源,基於zk,41位時間戳(毫秒數)+10位機器的ID+12位毫秒內的流水號+1位符號位(永遠是0);
UidGenerator:百度開源,基於snowflake演算法;
Leaf:美團開源,能保證全域性唯一性、高可用、趨勢遞增(不太安全,比如洩露公司訂單數量)、單調遞增等。
擴容會比較麻煩分庫分表通常的方案都用主鍵mod分表的數量,來把資料路由到某一個數據庫分片上。例如分了10張表,那麼就是ID%10,得到結果0-9,代表不同的表;但是當資料量進一步增多的時候,單庫的資料量達到了一定的級別之後,那麼就需要分更多的表,那麼這時候有哪些處理方案呢?
做資料遷移:最簡單暴力,也是最麻煩的一個方案;因為當分表(分庫)數量增多的時候,因為分片規則的變化,每個表的資料都要被重新分配到多個新的表;
如果id是一個增長的全域性序列,當前有十張表,那麼分表的演算法為:id%10,根據0-9路由到10個表中;當表擴到20張的時候,擴容那一刻取max_id,那麼未來分庫的演算法也就變成了:
if(id<max_id){id%10} else {id%20};有些分表的演算法本身就帶時間戳,可以基於id中的時間戳來實現,比如Snowflake演算法(見上文),這個演算法是一個64位的Long值,前42位就是一個精確到毫秒的時間戳,那麼我們的分庫演算法也就可以以某個時間點來判斷:
回覆列表
我從分庫分表存在的問題和怎麼做來回答一下這個問題。。
一,分庫分表的ID主鍵不能依賴於資料庫的自增,因為多庫中會重複!
通常使用外接的資料元件獲取全域性唯一的ID:比如加強型UUID(根據Ip,時間戳等得到)和使用Redis(RedisAtomicLong)和zookeeper的API獲取,Twitter的雪花演算法等等!
二,分庫分表之後的連線查詢比較困難!
問題沒法避免,通常拆分SQL,使用多次查詢,用查到的結果再分別查別的結果!
三,分散式事務的資料一致性很難保證!
可以使用TCC程式設計模型保證兩處的事務都能正確提交,但是這種方式對程式碼的侵入比較重!也可以使用基於訊息的資料一致性保證!
四,多資料的排序,分組,統計會比較困難!
1,用多執行緒,對多個節點分別查詢,然後彙總!
2,也可以提前冗餘查詢表,將所有的經常查詢的重點資料提前統一到個庫表裡!