這裡的部落格版本都不會被更新維護。檢視最新的版本請移步:http://neojos.com
全稱Universally Unique Identifier
,UUID
佔128bit
,也就是16個英文字元的長度(16byte
),需要強調的是,它的生成無需中心處理程式。
UUID
被用來標識URN(Uniform Resource Names)
,對於Transaction ID
以及其他需要唯一標誌的場景都可以使用它。
UUID
是空間和時間上的唯一標識,它長度固定,內部中包含時間資訊。如果伺服器時間存在不同步的情況,UUID
可能會出現重複。
UUID
構成
基本格式,由6部分組成:
time-low - time-mide - time-high-and-version - clock-seq-and-reserved & clock-seq-low - node
一個URN
示例:f81d4fae-7dec-11d0-a765-00a0c91e6bf6
。
因為UUID
佔128bit
,16進位制數佔4bit
,所以轉換成16進位制0-f
的字串總共有32位。組成的各個部分具體由幾位16進製表示,請查閱 Namespace Registration Template
因為UUID
太長且無序,導致其不適合做MySQL
的主鍵索引。而且MySQL
自帶的auto-increment
功能,選擇bigint
的話也只佔用64bit
。
All indexes other than the clustered index are known as secondary indexes. In
InnoDB
, each record in a secondary index contains the primary key columns for the row, as well as the columns specified for the secondary index.InnoDB
uses this primary key value to search for the row in the clustered index.If the primary key is long, the secondary indexes use more space, so it is advantageous to have a short primary key.
MongoDB`s ObjectId
ObjectId
由佔4-byte
的時間戳、3-byte
的機器標識、2-byte
的程式ID
以及3-byte
的計陣列成,總共還是佔用96bit
。
這些ID
組成包括時間、機器標識、隨機數,在UUID
生成時還使用到MAC
地址。這些引數中時間是關鍵,保證叢集伺服器的時鐘準確非常重要。
Twitter Snowflake
Twitter Snowflake
生成的ID
佔64bit
,跟bigint
大小一致。由41 bit
毫秒精度的時間戳、10bit
的機器ID
以及12 bit
的序列號組成(計數每4096就重新開始一輪),剩下的1 bit
奉獻給未來。
作者修改了它的原始設定,將剩下的1 bit
給了時間戳。使用機器MAC
地址的HASH
值作為當前機器的ID
。
服務全域性儲存最近一次生成ID
的時間戳lastTimestamp
,作為生成新ID
的判斷依據,避免時間回溯。詳細程式碼請參照[1]
。
// Block and wait till next millisecond
private long waitNextMillis(long currentTimestamp) {
while (currentTimestamp == lastTimestamp) {
currentTimestamp = timestamp();
}
return currentTimestamp;
}
同時將sequence
也宣告為全域性變數,每間隔4096次就重新開始計數。主要用於應對:當時間戳相同時保證生成的ID
是不同的。
if (currentTimestamp == lastTimestamp) {
sequence = (sequence + 1) & maxSequence;
if(sequence == 0) {
// Sequence Exhausted, wait till next millisecond.
currentTimestamp = waitNextMillis(currentTimestamp);
}
} else {
// reset sequence to start with zero for the next millisecond
sequence = 0;
}
Database Ticket Servers
該方式通過中心的DB
服務來生成唯一自增ID
,但DB
服務的寫操作會成為系統的瓶頸。如果後臺是單個DB
服務的話,存在單點問題。
參考Flickr
的方法,後臺使用兩個DB
來生成ID
,其中auto-increment
一個按照奇數步長增長,另一個按照偶數步長增長。MySQL
內部使用REPLACE
來實現,通過一條衝突的記錄,來持續生成自增的主鍵ID
。
REPLACE
makes sense only if a table has aPRIMARY KEY
orUNIQUE
index. Otherwise, it becomes equivalent toINSERT
, because there is no index to be used to determine whether a new row duplicates another.
結合Twitter Snowflake
對ID
做如下調整:41-bit
的毫秒時間戳、13-bit
的資料邏輯分割槽以及10-bit
的自增序列。自增序列對1024取餘,每個分割槽每毫秒內能生成1024
個自增ID
。
Flickr
中各個資料表按照不同的步長增長,當需要分表的時候就會存在巨複雜的資料遷移問題。為了解決這個問題,便引入了邏輯分割槽Shard ID
。通過邏輯上的Shard
,將資料分散在不同的資料表中。這樣後續的分庫分表都可以通過操作邏輯上Shard
來實現,將DB
從具體的實現中解脫出來。
關於獲取MySQL
自增ID
,程式碼無法批量獲取插入的全部自增ID
列表,MySQL
只會返回第一條記錄的自增ID
。因為自增ID
是連續的,所以可以通過計算的方式來計算出ID
列表。
If you insert multiple rows using a single
INSERT
statement,LAST_INSERT_ID()
returns the value generated for the first inserted row only. The reason for this is to make it possible to reproduce easily the sameINSERT
statement against some other server.
關於Shard
可以檢視本地快取BigCache
,很有參考意義(我覺得)。
總結
文中介紹了ID
的兩種生成方式,核心的區別在於:整個系統的ID
是否支援單調遞增。Twitter Snowflake
以及UUID
可以保證生成的資料唯一,但多臺伺服器的話,無法保證生成的資料有序。而Ticket Servers
通過結合MySQL
的auto-increment
解決了這個問題。
參考文章: