分布式系統(tǒng)中的唯一ID有哪些生成方式
在后端系統(tǒng)中,每條記錄都需要一個唯一的ID來進(jìn)行標(biāo)識。
雖然一開始聽起來可能很瑣碎,但在高度分布式的環(huán)境中生成全局唯一標(biāo)識符實(shí)際上是一個具有挑戰(zhàn)性的任務(wù)。

在本文中,讓我們來看一下一些常見的已知ID生成算法。
Ticket 服務(wù) - 集中式數(shù)據(jù)庫

使用自增功能生成ID
Ticket 服務(wù)解決方案利用 SQL 數(shù)據(jù)庫中的自增功能來生成唯一的ID。
使用集中式數(shù)據(jù)庫服務(wù)器,Web 服務(wù)器插入一個新記錄到數(shù)據(jù)庫中以生成一個自增的ID。
CREATE TABLE `ID` (
`id` bigint(20) unsigned NOT NULL auto_increment,
`stub` char(1) NOT NULL default '',
PRIMARY KEY (`id`),
UNIQUE KEY (stub)
);
REPLACE INTO ID (stub) VALUES ('a');
SELECT LAST_INSERT_ID();與使用 INSERT INTO 命令不同,我們可以使用 REPLACE INTO 命令來減少數(shù)據(jù)庫中的記錄數(shù)量。

REPLACE INTO 命令以原子方式原地更新單行,并獲取自增的主 ID,而無需創(chuàng)建新記錄。
優(yōu)點(diǎn):
- 實(shí)現(xiàn)簡單
- 生成的ID是64位的
- ID是順序且可排序的
缺點(diǎn):
- 只能使用1個表。多個表或數(shù)據(jù)庫將導(dǎo)致ID沖突
- 由于只使用了1個表,數(shù)據(jù)庫成為了單點(diǎn)故障
- 如果每秒的寫入數(shù)量巨大,將會有寫入瓶頸
Ticket 服務(wù) - 集群式數(shù)據(jù)庫

使用輪詢路由請求
與使用一個數(shù)據(jù)庫不同,我們可以使用多個具有偏移量的數(shù)據(jù)庫,以避免單點(diǎn)故障和寫入瓶頸。
偏移量 用于防止ID沖突。每個數(shù)據(jù)庫通過 k,k 是正在使用的數(shù)據(jù)庫服務(wù)器數(shù)量,增加其ID。
如上所示,如果使用了三個數(shù)據(jù)庫,每次生成ID時,自增的ID增加3。
優(yōu)點(diǎn):
- 相對容易實(shí)現(xiàn)
- 生成的ID是64位的
- 能夠在沒有單點(diǎn)故障的情況下處理高吞吐量
缺點(diǎn):
- 由于使用了多個數(shù)據(jù)庫,生成的ID不能保證是可排序的
- 難以水平擴(kuò)展。添加新數(shù)據(jù)庫很棘手,因?yàn)樗鼤绊懫屏俊?/li>
Twitter Snowflake
Snowflake方法在不依賴數(shù)據(jù)庫的情況下生成 64位的ID。

64位的ID被分成5個主要部分
ID分為5個主要部分:
- 時間戳(41位)
- 數(shù)據(jù)中心ID(5位)
- 機(jī)器ID(5位)
- 序列號(12位)
- 符號位(1位)
時間戳。自紀(jì)元以來的毫秒數(shù)。41位大約會在70年內(nèi)溢出,對于大多數(shù)項(xiàng)目的壽命來說是安全的。
數(shù)據(jù)中心ID。服務(wù)器所在的數(shù)據(jù)中心。如果兩個服務(wù)器在相同的時間收到相同的請求,則可以防止ID沖突。
機(jī)器ID。機(jī)器的ID。如果兩臺服務(wù)器在相似的數(shù)據(jù)中心中的相同時間收到相同的請求,則可以防止沖突。
序列號。對于在同一服務(wù)器上生成的每個ID,序列號會遞增1,并在每毫秒重置為0。這可以防止在同一服務(wù)器上的ID沖突。
優(yōu)點(diǎn):
- ID大致是有序的
- 能夠在沒有單點(diǎn)故障的情況下處理高吞吐量
- 能夠在機(jī)器之間無需協(xié)調(diào)地生成ID
- 能夠水平擴(kuò)展。
缺點(diǎn):
- ID不是完全有序的
- 未來的ID是可預(yù)測的。對于安全要求較高的應(yīng)用程序可能不理想
- 需要一個Zookeeper來跟蹤機(jī)器ID。
MongoDB ObjectID
MongoDB為每個新文檔創(chuàng)建一個唯一的對象ID。
對象ID由 MongoDB驅(qū)動程序生成而不是數(shù)據(jù)庫。這意味著可以在服務(wù)器上生成對象ID,而不依賴于MongoDB數(shù)據(jù)庫。

MongoDB對象ID是一個96位的ID
與Snowflake方法類似,MongoDB對象ID分為4個部分。對象ID是一個96位的ID。
- 時間戳(32位)
- 機(jī)器ID(24位)
- 進(jìn)程ID(16位)
- 計數(shù)器(24位)
大部分字段與Snowflake方法中提到的字段相似。
由于同一臺機(jī)器上可能運(yùn)行多個線程或進(jìn)程,因此進(jìn)程ID可以區(qū)分在不同進(jìn)程中由同一臺機(jī)器生成的對象ID。
優(yōu)點(diǎn):
- 能夠在沒有單點(diǎn)故障的情況下處理高吞吐量
- 能夠在機(jī)器之間無需協(xié)調(diào)地生成ID
- 能夠水平擴(kuò)展。
缺點(diǎn):
- 依賴第三方數(shù)據(jù)庫解決方案
- ID的長度為96位,而不是64位,需要更多的存儲空間。
UUID(通用唯一標(biāo)識符)

128位UUID的示例
通用唯一標(biāo)識符是一個128位的數(shù)字,包括多個部分,例如時間、節(jié)點(diǎn)的MAC地址或MD5哈希的命名空間。
有一組標(biāo)準(zhǔn)化的算法用于生成UUID,多年來已經(jīng)發(fā)布了5個不同版本的UUID,以適應(yīng)不同的需求。
這些算法相當(dāng)冗長,因此我們不會詳細(xì)介紹它們。我們將更多地關(guān)注它的優(yōu)缺點(diǎn)。
優(yōu)點(diǎn):
- 它是一個128位的ID,保證是唯一的
- 可以獨(dú)立生成,無需依賴任何第三方服務(wù)
- 它是隨機(jī)的和安全的。下一個ID是不可預(yù)測的。
缺點(diǎn):
- 它很大,在MySQL中索引不佳
- 它不是有序的
結(jié)論

在分布式環(huán)境中實(shí)現(xiàn)高度可擴(kuò)展和可用的ID生成器并不是微不足道的。





























