UUID 及其实现 2
上篇介绍了 UUID 的格式和 v4 的实现,这篇讲 v1 & v2 的实现。
v2 版本是 v1 上衍生出来的,而 v1 因为涉及到时间戳,又称为 time-based implementation。
实现 UUID v1
v1 除了常规的 variant 和 version 部份外,还涉及三个部分:
- timestamp,需要 60-bit 通常用 64-bit 容纳;非寻常的 Unix Timestamp
- clock sequence,需要 14-bit,通常用 16-bit 存储
- node identifier,48-bit 和设备相关
下面逐一解释这三个部分。
0x0. UUID Timestamp
和常见的 Unix 时间戳不同,UUID 时间戳记录的是,自 1582-10-15 00:00:00 至今的 100-ns 数。
1582年10月15日的零点是格里高力历开始的时间,这个时间也是 UUID Epoch Time。
UUID 时间戳的分辨率(resolution)是 100 纳秒,即每 100ns 为一个 tick。
现代编程语言都可以获取 unix 时间戳,因此可以先获取 unix 时间戳,然后加上两个 epoch time 的差值;这个差值是个定值,等于 122192928000000000
。
注意:获取时间戳时需要注意系统或者语言库能提供的分辨率。
0x1. Clock Sequence
因为引入了时间戳,所以存在可能由于时钟回拨、闰秒,甚至因为系统提供的时钟分辨率不够导致使用了重复的时间戳。
另外 node identifier 也有可能被改变。
所以为了尽可能保证 UUID 的唯一性,引入了 clock sequence。
注:RFC 4122 没有规定 UUID v1 必须要使用 steady clock,所以使用能够被回拨的 system clock 也是允许的。另外,即使使用了 steady clock,机器在两次启动之间也可能调整了硬件时间,一样可能会导致回拨。
Clock sequence 一开始会被初始化为一个随机值;之后如果某次获取 UUID 时间戳发现 <= 上一次的时间戳,就会自增 clock sequence。
clock sequence 通常会设置为一个无符号数,以确保溢出 wrap-around 的行为是确定的。