分佈式數據庫唯一ID生成方式

分佈式系統中我們會對一些數據量大的業務進行分拆,如:用戶表,訂單表。因為數據量巨大一張表無法承接,就會對其進行分庫分表。

但一旦涉及到分庫分表,就會引申出分佈式系統中唯一主鍵ID的生成問題,永不遷移數據和避免熱點的文章中要求需要唯一ID的特性:

  • 整個系統ID唯一
  • ID是數字類型,而且是趨勢遞增的
  • ID簡短,查詢效率快

什麼是遞增?如:第一次生成的ID為12,下一次生成的ID是13,再下一次生成的ID是14。這個就是生成ID遞增。

什麼是趨勢遞增?如:在一段時間內,生成的ID是遞增的趨勢。如:再一段時間內生成的ID在【0,1000】之間,過段時間生成的ID在【1000,2000】之間。但在【0-1000】區間內的時候,ID生成有可能第一次是12,第二次是10,第三次是14。

1.數據庫自增ID

新建一個公共庫,庫裡面新建一個序列表,主鍵id自增,每次請求增加數據都往這個表中插入數據,然後獲取到id,然後使用即可。

優點:方便簡單

缺點:單庫生成自增id,高併發下,會有瓶頸

適用場景:

併發很低,幾百/s,不會出現性能瓶頸

2.UUID

優點:本地生成,不基於任何第三方

缺點:

  • 太長,作為數據庫主鍵性能太差,不適合作為主鍵
  • 不具有有序性,會導致B+樹索引在寫的時候有過多的隨機寫操作(連續的id可以產生部分順序寫)
  • 寫的時候不能產生有順序的 append 操作,而需要進行 insert 操作,將會讀取整個 B+ 樹節點到內存,在插入這條記錄後會將整個節點寫回磁盤,這種操作在記錄佔用空間比較大的情況下,性能下降明顯

適用場景:

隨機生成文件名、編號,生成token等。

3.系統時間+拼接業務字段值

例如:當前時間戳 + 用戶id + 業務含義編碼,併發高的時候,會有重複,此時就不行了,不建議使用。

4.Redis

Redis是單線程的,所以也可以用生成全局唯一的ID。可以用Redis的原子操作 INCR和INCRBY來實現。

優點:

  • 不依賴於數據庫,靈活方便,且性能優於數據庫。
  • 數字ID天然排序,對分頁或者需要排序的結果很有幫助。

缺點:

  • 由於redis是內存的KV數據庫,即使有AOF和RDB,但是依然會存在數據丟失,有可能會造成ID重複。
  • 依賴於redis,redis要是不穩定,會影響ID生成。

5.雪花snowflake算法

twitter開源的分佈式id生成算法,把一個64位的long型的id,1個bit是不用的,用其中的41 bit作為毫秒數,用10 bit作為工作機器id,12 bit作為序列號,理論上最多支持1024臺機器每秒生成4096000個序列號。

分佈式數據庫唯一ID生成方式

  • 1 bit:不用
    因為二進制裡第一個bit為如果是1,那麼都是負數,但是我們生成的id都是正數,所以第一個bit統一都是0
  • 41 bit:表示的是時間戳,單位是ms
    41 bit可以表示的數字多達2^41 - 1,也就是可以標識2 ^ 41 - 1個毫秒值,換算成年就是表示69年的時間
  • 10 bit:記錄工作機器id
    代表的是這個服務最多可以部署在2^10臺機器上哪,也就是1024臺機器,但是10 bit裡5個bit代表機房id,5個bit代表機器id。意思就是最多代表2 ^ 5個機房(32個機房),每個機房裡可以代表2 ^ 5個機器(32臺機器)。
  • 12 bit:記錄同一個毫秒內產生的不同id
    12 bit可以代表的最大正整數是2 ^ 12 - 1 = 4096,也就是說可以用這個12bit代表的數字來區分同一個毫秒內的4096個不同的id

缺點:

  • 依賴機器的時鐘,如果服務器時鐘回撥,會導致重複ID生成

優點:

  • 此方案每秒能夠產生409.6萬個ID,性能快
  • 時間戳在高位,自增序列在低位,整個ID是趨勢遞增的,按照時間有序遞增
  • 靈活度高,可以根據業務需求,調整bit位的劃分,滿足不同的需求


分享到:


相關文章: