前言
隨著業(yè)務的發(fā)展毫胜,單一數(shù)據(jù)庫的自增ID已經(jīng)不能滿足我們的需求,使用全局唯一ID的場景必然會出現(xiàn)诬辈,比如海量的訂單號酵使,檔案號等等。我們初始可能會選擇使用36位的UUID焙糟,配合機器id和時間戳口渔,基本可以滿足需求。
但是UUID的缺點也很明顯穿撮,由于其完全無序缺脉,對MySQL的B+樹結(jié)構(gòu)特別不友好。另外UUID的長度也會造成數(shù)據(jù)庫索引空間的浪費悦穿。
由此產(chǎn)生的需求
- 全局唯一:不能重復攻礼,這是最基本的要求。
- 趨勢遞增:生成的ID是有序遞增的栗柒,這樣數(shù)據(jù)庫存儲索引數(shù)據(jù)時可以保證寫入性能礁扮。
- 信息安全:生成的ID不能是簡單連續(xù)遞增的,必須是大致遞增。如果是連續(xù)的太伊,那么惡意用戶可以很簡單地爬取我們的數(shù)據(jù)雇锡;而對于訂單號這種敏感的數(shù)據(jù),競爭對手更是可以輕松推算出我們一天的單量僚焦。
解決方案:雪花算法
雪花算法(Snowflake)是Twitter開源的一種生成分布式全局唯一ID的算法锰提,產(chǎn)生的背景是為了滿足Twitter每秒上萬條消息的請求,這些消息為了不重復必須有一個全局唯一的ID芳悲,并且還需要有大致的順序立肘,以滿足存儲性能要求及客戶端排序。
其默認生成結(jié)果是一個64bit的long型數(shù)值名扛,組成部分包含時間戳谅年,并且保持了大致遞增。
雪花算法核心結(jié)構(gòu)
如圖所示罢洲,組成一共包含4個部分:
- 不使用:1bit踢故,最高位bit默認為0,不使用惹苗;
- 時間戳:41bit殿较,毫秒級的時間戳,可以支持該算法使用到2082年桩蓉;建議使用64位Linux系統(tǒng)機器淋纲,通過vdso,gettimeofday()在用戶態(tài)就可以完成操作院究,減少了進入內(nèi)核態(tài)的損耗洽瞬。
- 機器標識:10bit可以支持1024臺機器,通常會將其拆分為兩部分业汰,5bit代表數(shù)據(jù)中心ID伙窃,5bit代表工作機器ID。
- 序列號:12bit遞增序列號样漆,就是一系列的自增id为障,每秒最多生成4096個不重復的ID。
通過這4部分放祟,雪花算法可以在1秒內(nèi)生成約409萬個ID鳍怨,已經(jīng)基本滿足絕大部分的業(yè)務需求署咽。
由于雪花算法生成的ID是大致遞增的客扎,非常契合MySQL中B+樹的結(jié)構(gòu),應用到數(shù)據(jù)庫的主鍵時卧蜓,可以極大的提升插入效率眉撵。
另外由于其是大致遞增侦香,而不是順序遞增落塑,直接將生成結(jié)果作為如訂單號這樣的業(yè)務字段也沒問題,可以保證第三方無法推斷出真實的訂單量鄙皇。
雪花算法生成ID重復的問題及解決方案
雖然雪花算法通過不同的組成盡量避免了ID重復芜赌,但是在某些極限情況下仰挣,依然無法排除ID重復的發(fā)生伴逸。
- 情況1:時鐘回撥,雪花算法強依賴機器時鐘膘壶,如果機器上時鐘回撥错蝴,會造成發(fā)號重復。
- 情況2:在某一毫秒內(nèi)颓芭,某些節(jié)點上的機器標識一致顷锰,并且產(chǎn)生了同一個序列號。
針對情況1亡问,我們可以維護一個上次生產(chǎn)ID的時間戳lastTimestamp官紫,每次發(fā)號后更新lastTimestamp,發(fā)號前則對比當前時間戳和lastTimestamp州藕,當前時間戳比lastTimestamp小束世,就強制等待兩者時間差后再發(fā)號,但這會造成發(fā)號服務處于不可用的狀態(tài)床玻。
針對情況2毁涉,既然時間戳和序列號我們無法保證不重復,那就從機器標識下手锈死。只要機器標識不重復贫堰,生成的ID自然也不會重復了。如果我們的項目部署是機器級別待牵,即一臺機器上部署一套服務其屏,那以機器MAC地址作為機器標識就可以。如果是進程級別缨该,即一臺機器上部署多套相同的服務偎行,僅僅是PID不同,這種情況下可以通過引入Redis压彭、Zookeeper或者MySQL來保證機器標識位的唯一性睦优。
國內(nèi)開源的分布式ID框架
對于雪花算法可能重復的問題,國內(nèi)也有一些開源的框架作為替代壮不,比如MT的leaf汗盘、BD的Uid。
總得來說询一,雪花算法已經(jīng)可以滿足絕大部分場景隐孽,如果沒有十分必要的話癌椿,還是不建議引入開源方案,畢竟會大大增加我們系統(tǒng)的復雜度菱阵。
總結(jié)
本文主要講解了什么是雪花算法踢俄,雪花算法適用的場景以及如何解決雪花算法沖突的問題。
當然雪花算法也不是萬能的晴及,不能適用所有的場景都办,建議大家根據(jù)實際的業(yè)務進行評估,然后選擇合適的方案虑稼。
?
學習技術(shù)琳钉,分享技術(shù),期待與大家共同進步蛛倦,也感謝您的點贊與關(guān)注歌懒。