下面有幾種常用方案,可以根據具體業務場景來選擇。
1. UUID
UUID 指在一臺機器上生成的數字,它保證在同一時空中的所有機器都是唯一的。
UUID 由以下幾部分組成:
- 當前日期和時間。
- 時鐘序列。
- 全局唯一的IEEE機器識別碼(如網卡MAC地址等)。
在Java中,使用UUID 非常方便。
UUID uuid = UUID.randomUUID();
UUID 具有如下優點:
- 使用方便,很容易實現。
- 性能很高。
缺點:
- 沒有順序,不能保證單調遞增。
- 太長,總長32位,無論是存儲還是傳輸,缺點都比較明顯。
2. SnowFlake 雪花算法
Twitter 的SnowFlake 是一個非常優秀的ID生成方案,實現也比較簡單,8Byte 是一個Long,等於64bit,核心代碼就是毫秒級時間41位+10位機器ID+毫秒序列12位。
https://github.com/twitter-archive/snowflake
SnowFlake 的優點如下:
- 比UUID 短,一般為9-17位。
- 生成的ID是數字,可以做到單調遞增。由於無法統一分佈式環境中每臺服務器的時鐘,它只能做到單臺機器單調遞增,無法做到全局遞增。
- 性能非常出色,吞吐量達到幾十萬TPS。
SnowFlake的結構如下(每部分用-分開):
0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000
第一位為未使用,接下來的41位為毫秒級時間(41位的長度可以使用69年),然後是5位DataCenterID和5位WorkerID(10位的長度最多支持部署1024個節點) ,最後12位是毫秒內的計數(12位的計數順序號支持每個節點每毫秒產生4096個ID序號)。
一共加起來剛好64位,為一個Long型。(轉換成字符串後長度最多19)
SnowFlake 生成的ID整體上按照時間自增排序,並且整個分佈式系統內不會產生ID碰撞(由DataCenterID和WorkerID作區分),並且效率較高。經測試SnowFlake 每秒能夠產生26萬個ID。
如下SnowFlake 算法生成的2進制和Long 型的唯一ID。
關於《SnowFlake-Java版雪花算法》實現方案和演示,可以查看小編的另外一篇文章。
3. Ticket Server
Ticket Server 是 Flickr 採用的一種分佈式ID 生成方案,利用 MySQL 自增長ID 實現。
它的設計思路是利用數據庫中 auto increment 的特性和MySQL 特有的 REPLACE INTO 命令來實現,可以利用多臺MySQL 實現高擴展性和高可用性。
比如以 2 臺MySQL 服務器實例,分別進行配置。
節點一配置:
auto_increment_increment = 2;
auto_increment_offset = 1;
節點二配置:
auto_increment_increment = 2;
auto_increment_offset = 2;
上述配置最好放到配置文件中,否則MySQL 服務器重啟將丟失設置。
然後分別在2個庫裡面,建表,如tickets,設置ENGINE=MyISAM,表級鎖,能保證所有 REPLACE INTO 的原子性。不斷通過 REPLACE INTO 促使ID 自增,這樣表中只有一條記錄。
REPLACE INTO tickets (stub) VALUES ('a')
在同一個連接內,通過 last insert id 獲取自增的ID 值。
Ticket Server 的優點:
- 對於數據量不是特別大的應用場景,長度最小。
- 如果已經有應用基於 MySQL 的自增ID,那麼採用此方案非常容易遷移,而且兼容性好。
這個方案沒有絕對的順序,只能有一個近似的順序,有可能在某個MySQL 實例的狀態跑得快。
總結
如果在高併發、大數據量的情況下,建議採用 SnowFlake 方案,性能突出。
對於並非不大,並且需要兼容老業務的場景下,可以使用 Ticket Server方案,2臺MySQL 物理機也能輕鬆達到 幾萬TPS,響應時間在毫秒級。
閱讀更多 軟件架構 的文章