如何生成全局唯一id

為什么需要全局唯一id

在分布式架構(gòu)下,經(jīng)常有需求需要生成全局唯一id,比如優(yōu)惠券等券碼,或者分庫分表,每個表都用自增id,會導致每個表的id都不唯一,都需要生成全局唯一id。
這里介紹幾種分布式架構(gòu)下全局唯一id的生成方式,然后再結(jié)合具體場景說下實際項目中遇到哪些問題和解決方案,最后介紹下美團的全局唯一id生成服務(wù)leaf的實現(xiàn)。

常用解決方案

一、UUID

這是最容易想到的方案,UUID(Universally Unique Identifier)是32個16進制數(shù)字,以連字號分為五段,形式為8-4-4-4-12的36個字符,目前生成方式有5種,可參考A Universally Unique IDentifier (UUID) URN Namespace
好處就是生成很簡單,每個系統(tǒng)本地生成就可以。
壞處更加明顯,就是太長和無序,會導致以下問題:
1、很多業(yè)務(wù)場景不適用,比如優(yōu)惠券的發(fā)放,可能12位的券池就能滿足發(fā)放的需要了,太長不但不易于存儲,還會導致無法用于券碼的展示
2、不利于做索引。mysql存儲時,uuid的長度太長不利于做主鍵,而且無序性會導致作為主鍵插入時數(shù)據(jù)位置頻繁變動,影響性能
所以,很多場景或者用于主鍵的情況下,都不能使用uuid

二、數(shù)據(jù)庫自增主鍵

可以創(chuàng)建一個表,通過數(shù)據(jù)插入獲取對應(yīng)的自增主鍵,作為全局唯一id
缺點也很明顯,就是高并發(fā)的場景下,受限于單臺mysql的性能。而且可用性差,DB出現(xiàn)問題會導致id無法生成。
當然可以通過主從的方式增強可用性,同時增加表采用不同自增步長的方式增加并發(fā)性能,比如假設(shè)我們要部署N臺機器,步長需設(shè)置為N,每臺的初始值依次為0,1,2…N-1;但是還會帶來新的問題,比如不利于拓展,想提升性能就要堆機器,但是步長已經(jīng)確定不好更改,主從延遲會導致唯一id的不唯一,。

三、snowflake

這是twitter開源的分布式id生成算法,這種方案把64-bit分別劃分成多段,分開來標示機器、時間等,比如在snowflake中的64-bit分別表示如下圖(圖片來自網(wǎng)絡(luò))所示:


image.png

上面第一個部分,是1個bit:0,這個是無意義的上面第二個部分是41個bit:表示的是時間戳;上面第三個部分是5個bit:表示的是機房id,10001上面第四個部分是5個bit:表示的是機器id,1 1001上面第五個部分是12個bit:表示的序號,就是某個機房某臺機器上這一毫秒內(nèi)同時生成的id的序號,0000 00000000
優(yōu)點就是靈活,5位可以用來做業(yè)務(wù)標識
缺點呢就是比較依賴時鐘

實際應(yīng)用

場景一:分庫分表后數(shù)據(jù)唯一id

需求:

  • id要作為主鍵,即要滿足趨勢遞增
  • id長度盡量小
    這種場景我們在項目中使用了數(shù)據(jù)庫自增主鍵的方式,創(chuàng)建了32張表,步長32并設(shè)置遞增初始值的方式,生成唯一id,可以較好的滿足該場景。

場景二:團購券券碼

需求:

  • 券碼唯一且不能趨勢遞增,不然用戶會猜測券碼,不安全
  • 券碼長度控制在可接受范圍
    這種場景項目中用了碰撞的方式,隨機生成的固定長度券碼保存在券碼表,券碼唯一索引,job定時補充券碼表并撈取可用券碼到緩存券池。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容