全域性主鍵避重問題

2021-10-18 12:28:32 字數 1554 閱讀 2726

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。

******xx-***x-m***-n***-************

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 語句的時候,比如插入,它應該是在哪個資料節點上面執行呢?又比如查詢,如果只在其中的乙個節點上面,我怎麼知道在哪個節點,是不是要在所有的資料庫節點裡面都查詢一遍,才能拿到結果?

那麼,從客戶端到服務端,我們可以在哪些層面解決這些問題呢?

分表解決主鍵 Mysql分片分表全域性主鍵避重問題

在分庫分表環境中,由於表中資料同時存在不同資料庫中,主鍵值平時使用的自增長將無用武之地,某個分割槽資料庫自生成的id無法保證全域性唯一。因此需要單獨設計全域性主鍵,下面是幾種生成唯一id的方式方法 1 uuid uuid標準形式包含32個16進製制數字,分為5段,形式為8 4 4 4 12的36個字...

各種全域性主鍵生成策略對比

優點 簡單 唯一 遞增 增幅固定 缺點 寫效能決定每秒生成數量上限,擴充套件差 分布式資料庫,主節點掛掉,備節點上時可能有問題 主節點寫入成功,日誌未同步到備節點,導致id重複 備註 可有乙個寫庫變成多個庫同時寫,如1 2 3三個庫同時寫,初始id分別為1 2 3,自增幅度都為3。這種方式可保證id...

各種全域性主鍵生成策略對比

優點 簡單 唯一 遞增 增幅固定 缺點 寫效能決定每秒生成數量上限,擴充套件差 分布式資料庫,主節點掛掉,備節點上時可能有問題 主節點寫入成功,日誌未同步到備節點,導致id重複 備註 可有乙個寫庫變成多個庫同時寫,如1 2 3三個庫同時寫,初始id分別為1 2 3,自增幅度都為3。這種方式可保證id...