什麼是 UUID? 相信多數參與軟體開發的人應該都知道 。 知道什麼是 UUID, 暸解 TimeUUID 也是輕而易舉的事情 。 雖然 TimeUUID 感覺無足輕重 , 但在特定的使用案例 (use case), 又是這麼方便 , 山姆鍋覺得值得為它介紹一番 。

何謂 UUID?

UUID, 是 Universally Unique Identifier 的縮寫 , 中文可以翻譯為 「 通用唯一識別碼 」。 軟體常常需要使用識別碼 (identifier) 來辨識不同實體或物件 , 這樣的識別碼也常常使用在資料庫中作為主鍵 (Primary key)。 UUID 跟其它識別碼相比 , 主要特點在於 :

  1. 不同的系統可以各自產生 UUID, 不需要中央資料庫或服務協助 。
  2. 由各自系統產生的 UUID 衝突 ( 產生相同 UUID) 的機率很低 , 低到可以忽略 。

所以 , 對於需要使用識別碼 , 卻又不能或者不想使用中央資料庫的系統 ,UUID 便成為很有吸引力的選擇 。 當然如果應用 (applications) 一定不能出現重複的代碼 , 且發生重複時無法處理 ,UUID 自然不適合 。 另外 , 因為 UUID 需要較多的位元組 (16 bytes) 才能表示 , 對於不能接受使用這麼大容量的應用也不適合 。 除非是儲存容量或者頻寬真的非常小 , 不然 UUID 的長度已經不是使用上主要的考量 。

何謂 TimeUUID?

簡單地說 :TimeUUID 是一種 UUID, 跟 UUID 相比多了下列特性 :

  • 同一系統產生的 TimeUUID, 後產生的 TimeUUID 在位元組排序上一定比較大 。

以另一個方式解釋 , 因為 UUID 跟 TimeUUID 在記憶體內部通常以 16 個 bytes 或者轉成 16 進位表示的字串 , 使用按照字母順序 (Alphabetically) 由小到大排序 , 後產生的 TimeUUID 一定排在後面 。

這個特點對於軟體開發有什麼用處 ?

TimeUUID 的用途

隨著物聯網 (Internet of Things) 的流行 [1] , 越來越多的資料都需要以發生時間順序來排序 。 由於這些事件發生的頻率可能高過系統時鐘的解析度 (resolution) [2] , 直接以系統時間當作識別碼並不可行 。 這種情況下 , TimeUUID 便成為一個簡單的方案 。

另外以訊息傳輸 (messaging) 為例 , 同一組訊息 (messages), 不管訊息的來源 , 不管接收的順序 , 假設沒有遺失的條件下 , 所有接收者最終都可以得到相同的排序 。 TimeUUID 單純的時間特性 , 使得它非常適合這種去中央化 (decentralized) 的方式決定訊息的順序 。

TimeUUID 實作

許多不同的程式語言都有 TimeUUID 的實作 。 Python 有個 time-uuid 套件可以使用 , 以下是該專案提供的範例 :

>>> import random, time_uuid
>>> rand_time = lambda: float(random.randrange(0,30))+time_uuid.utctime()
>>> uuids = [time_uuid.TimeUUID.with_timestamp(rand_time()) for i in xrange(3)]
[TimeUUID('2e4ac100-31f1-11e2-9286-14109fcdd33b'),
TimeUUID('2db393a2-31f1-11e2-abda-14109fcdd33b'),
TimeUUID('2987779e-31f1-11e2-a699-14109fcdd33b')]
>>> list(sorted(uuids))
[TimeUUID('2987779e-31f1-11e2-a699-14109fcdd33b'),
TimeUUID('2db393a2-31f1-11e2-abda-14109fcdd33b'),
TimeUUID('2e4ac100-31f1-11e2-9286-14109fcdd33b')]

結語

山姆鍋最常使用 TimeUUID 來作為訊息的鍵值 (key), 使用 TimeUUID 來查詢最新或者一定時間範圍內的訊息 。 只要是需要依照時間排序又需要避免重複 (conflict) 的情況 ,TimeUUID 就是一個很好用的時間標記 。


[1] 山姆鍋也來湊熱鬧 , 硬是用物聯網當例子 。
[2] 指系統時鐘變動的最小值 , 例如 : 時鐘每秒 100 次變動 , 則間隔最少為 10ms。