
對比
UUID
UUID (Universally Unique Identifier) 的標準型式包含 32 個 16 進制數(shù)字,以連字號分為五段,形式為 8-4-4-4-12 的 36 個字符,示例:550e8400-e29b-41d4-a716-446655440000,到目前為止業(yè)界一共有 5 種方式生成 UUID
-
優(yōu)點:
- 性能非常高:本地生成,沒有網(wǎng)絡消耗。
-
缺點:
- 不易于存儲:UUID 太長,16 字節(jié) 128 位,通常以 36 長度的字符串表示,很多場景不適用。
- 信息不安全:基于 MAC 地址生成 UUID 的算法可能會造成 MAC 地址泄露,這個漏洞曾被用于尋找梅麗莎病毒的制作者位置。
- ID 作為主鍵時在特定的環(huán)境會存在一些問題,比如做 DB 主鍵的場景下,UUID 就非常不適用:
注意:
- MySQL 官方有明確的建議主鍵要盡量越短越好 [4],36 個字符長度的 UUID 不符合要求
- 對 MySQL 索引不利:如果作為數(shù)據(jù)庫主鍵,在 InnoDB 引擎下,UUID 的無序性可能會引起數(shù)據(jù)位置頻繁變動,嚴重影響性能
SNOWFLAKE 雪花算法
雪花算法是由 Twitter 公布的分布式主鍵生成算法,它能夠保證不同進程主鍵的不重復性,以及相同進程主鍵的有序性。在同一個進程中,它首先是通過時間位保證不重復,如果時間相同則是通過序列位保證。 同時由于 時間位是單調遞增的,且各個服務器如果大體做了時間同步,那么生成的主鍵在分布式環(huán)境可以認為是總體有序的,這就保證了對索引字段的插入的高效性。例如 MySQL 的 Innodb 存儲引擎的主鍵。
使用雪花算法生成的主鍵,二進制表示形式 包含 4 部分,從高位到低位分表為:1bit 符號位、41bit 時間戳位、10bit 工作進程位以及 12bit 序列號位。
- 符號位 (1bit)
預留的符號位,恒為零。
- 時間戳位 (4bit)
41 位的時間戳可以容納的毫秒數(shù)是 2 的 41 次冪,一年所使用的毫秒數(shù)是:365 * 24 * 60 * 60 * 1000。通過計算可知:
Math.pow(2, 41) / (365 * 24 * 60 * 60 * 1000L);
結果約等于 69.73 年。ShardingSphere 的雪花算法的時間紀元從 2016 年 11 月 1 日零點開始,可以使用到 2086 年,相信能滿足絕大部分系統(tǒng)的要求。
-
工作進程位 (10bit)
該標志在 Java 進程內是唯一的,如果是分布式應用部署應保證每個工作進程的 id 是不同的。該值默認為 0,可通過屬性設置。 - 序列號位 (12bit)
該序列是用來在同一個毫秒內生成不同的 ID。如果在這個毫秒內生成的數(shù)量超過 4096 (2 的 12 次冪),那么生成器會等待到下個毫秒繼續(xù)生成。
注意: 該算法存在 時鐘回撥 問題,服務器時鐘回撥會導致產生重復序列,因此默認分布式主鍵生成器提供了一個最大容忍的時鐘回撥毫秒數(shù)。 如果時鐘回撥的時間超過最大容忍的毫秒數(shù)閾值,則程序報錯;如果在可容忍的范圍內,默認分布式主鍵生成器會等待時鐘同步到最后一次主鍵生成的時間后再繼續(xù)工作。 最大容忍的時鐘回撥毫秒數(shù)的默認值為 0,可通過屬性設置。