我是山姆鍋

什麼是 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 套件可以使用, 以下是該專案提供的範例:

1
2
3
4
5
6
7
8
9
10
>>> 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。 ↩︎