全局主键避重问题
MySQL 的數據庫里面字段有一個自增的屬性,Oracle 也有Sequence 序列。如果是一個數據庫,那么可以保證ID 是不重復的,但是水平分表以后,每個表都按照自己的規律自增,肯定會出現ID 重復的問題,這個時候我們就不能用本地自增的方式了。
我們有幾種常見的解決方案:
1)UUID(Universally Unique Identifier 通用唯一識別碼)
UUID 標準形式包含32 個16 進制數字,分為5 段,形式為8-4-4-4-12 的36 個字符,例如:c4e7956c-03e7-472c-8909-d733803e79a9。
xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
M 表示UUID 版本,目前只有五個版本,即只會出現1,2,3,4,5,數字N 的一至三個最高有效位表示UUID 變體,目前只會出現8,9,a,b 四種情況。
1、基于時間和MAC 地址的UUID
2、基于第一版卻更安全的DCE UUID
3、基于MD5 散列算法的UUID
4、基于隨機數的UUID——用的最多,JDK 里面是4
5、基于SHA1 散列算法的UUID
?UUID 是主鍵是最簡單的方案,本地生成,性能高,沒有網絡耗時。但缺點也很明顯,由于UUID 非常長,會占用大量的存儲空間;另外,作為主鍵建立索引和基于索引進行查詢時都會存在性能問題,在InnoDB 中,UUID 的無序性會引起數據位置頻繁變動,導致分頁。
2) 數據庫
把序號維護在數據庫的一張表中。這張表記錄了全局主鍵的類型、位數、起始值,當前值。當其他應用需要獲得全局ID 時,先for update 鎖行,取到值+1 后并且更新后返回。并發性比較差。
3)Redis
基于Redis 的INT 自增的特性,使用批量的方式降低數據庫的寫壓力,每次獲取一段區間的ID 號段,用完之后再去數據庫獲取,可以大大減輕數據庫的壓力。
4)雪花算法Snowflake(64bit)
核心思想:
a)使用41bit 作為毫秒數,可以使用69 年
b)10bit 作為機器的ID(5bit 是數據中心,5bit 的機器ID),支持1024 個節點
c)12bit 作為毫秒內的流水號(每個節點在每毫秒可以產生4096 個ID)
d)最后還有一個符號位,永遠是0。
代碼:snowflake.SnowFlakeTest
優點:毫秒數在高位,生成的ID 整體上按時間趨勢遞增;不依賴第三方系統,穩定性和效率較高,理論上QPS 約為409.6w/s(1000*2^12),并且整個分布式系統內不會產生ID 碰撞;可根據自身業務靈活分配bit 位。
不足就在于:強依賴機器時鐘,如果時鐘回撥,則可能導致生成ID 重復。
當我們對數據做了切分,分布在不同的節點上存儲的時候,是不是意味著會產生多個數據源?既然有了多個數據源,那么在我們的項目里面就要配置多個數據源。
現在問題就來了,我們在執行一條SQL 語句的時候,比如插入,它應該是在哪個數據節點上面執行呢?又比如查詢,如果只在其中的一個節點上面,我怎么知道在哪個節點,是不是要在所有的數據庫節點里面都查詢一遍,才能拿到結果?
那么,從客戶端到服務端,我們可以在哪些層面解決這些問題呢?
?
總結
- 上一篇: 排序、翻页、函数计算问题
- 下一篇: 主从复制的含义