{eval=Array;=+count(Array);}
我從分庫分表存在的問題和怎么做來回答一下這個問題。。
一,分庫分表的ID主鍵不能依賴于數據庫的自增,因為多庫中會重復!
通常使用外接的數據組件獲取全局唯一的ID:比如加強型UUID(根據Ip,時間戳等得到)和使用Redis(RedisAtomicLong)和zookeeper的API獲取,Twitter的雪花算法等等!
二,分庫分表之后的連接查詢比較困難!
問題沒法避免,通常拆分SQL,使用多次查詢,用查到的結果再分別查別的結果!
三,分布式事務的數據一致性很難保證!
可以使用TCC編程模型保證兩處的事務都能正確提交,但是這種方式對代碼的侵入比較重!也可以使用基于消息的數據一致性保證!
四,多數據的排序,分組,統計會比較困難!
1,用多線程,對多個節點分別查詢,然后匯總!
2,也可以提前冗余查詢表,將所有的經常查詢的重點數據提前統一到個庫表里!
分庫分表涉及到的知識點比較多,建議使用專門的分庫分表組件!本人有mycat使用經驗,如果您有相關問題,歡迎前來探討!
數據庫在做了分庫分表之后,關于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位就是一個精確到毫秒的時間戳,那么我們的分庫算法也就可以以某個時間點來判斷:
if(id中的時間<增加分表那一刻的時間){id%10} else {id%20};
數據量達到查詢瓶頸的時候,需要做一些拆分或索引優化處理。
對于使用id主鍵來說,分庫分表都要做一些特別的設計,有以下幾個方案。
1、id區間提前規劃好,每個庫分配好整數區間,每個庫中的每個表也要規劃號,數字那么大,總有區間能夠容納下增長的數字。
2、id采用32位全局uuid保證唯一
3、通過雪花算法,得到分布式環境下全局唯一的id
4、采用納秒級時間戳+隨機數+重試機制保證數據唯一。
由于數據庫的索引大部分采用B+數數據結構來存儲,主鍵的線性遞增對數據的插入(B+樹的拆分和合并)和查詢性能有優勢,所以建議采用能保證主鍵遞增的方案。
全局id生成算法 snowklake算法 用long型64位表示 1位表示符號位正整數 41位表示時間戳 10位表示機器碼 12位表示順序位
為什么要分物理表呢? 分區的底層同樣是物理分表但上層MySQL已做好一切展現給我們的是一個總表,不同的數據放到不同分區,CURD甚至索引完全就是當成一個表來操作,其實展現給用戶的就是一張表,但底層分成了若干個區
0
回答0
回答1
回答0
回答0
回答0
回答0
回答0
回答0
回答0
回答