主题
UUID 算法
UUIDv7 (时间顺序排序)
UUIDv7 与广泛使用的 UUIDv4 等同类产品一样,都是 128 位唯一标识符。但与 v4 不同的是,UUIDv7 可进行时间排序,精度为 1 毫秒。通过结合时间戳和随机部分,UUIDv7 成为数据库(包括分布式数据库)中记录标识符的绝佳选择。
结构
128 位数值由几个部分组成:
- timestamp (48 bits) 是以毫秒为单位的 Unix 时间戳。
- ver (4 bits) 是 UUID 版本 (7)。
- rand_a (12 bits) 是随机生成的。
- var* (2 bits) 等于 10
- rand_b (62 bits) 是随机生成的。
TIP
*
在字符串表示法中,每个符号编码 4 位十六进制数,因此示例中的 a 是 1010,其中前两位是固定变量(10),后两位是随机数。 因此得到的十六进制数可以是 8 (1000)、9 (1001)、a (1010) 或 b (1011)。
0190163d-8694-739b-aea5-966c26f8ad91
└─timestamp─┘ │└─┤ │└───rand_b─────┘
ver │var
rand_a
实现
java
import java.nio.ByteBuffer;
import java.security.SecureRandom;
import java.util.UUID;
public class UUIDv7 {
private static final SecureRandom random = new SecureRandom();
public static UUID randomUUID() {
byte[] value = randomBytes();
ByteBuffer buf = ByteBuffer.wrap(value);
long high = buf.getLong();
long low = buf.getLong();
return new UUID(high, low);
}
public static byte[] randomBytes() {
// random bytes
byte[] value = new byte[16];
random.nextBytes(value);
// current timestamp in ms
ByteBuffer timestamp = ByteBuffer.allocate(Long.BYTES);
timestamp.putLong(System.currentTimeMillis());
// timestamp
System.arraycopy(timestamp.array(), 2, value, 0, 6);
// version and variant
value[6] = (byte) ((value[6] & 0x0F) | 0x70);
value[8] = (byte) ((value[8] & 0x3F) | 0x80);
return value;
}
public static void main(String[] args) {
var uuid = UUIDv7.randomUUID();
System.out.println(uuid);
}
}
python
import os
import time
def uuidv7():
# random bytes
value = bytearray(os.urandom(16))
# current timestamp in ms
timestamp = int(time.time() * 1000)
# timestamp
value[0] = (timestamp >> 40) & 0xFF
value[1] = (timestamp >> 32) & 0xFF
value[2] = (timestamp >> 24) & 0xFF
value[3] = (timestamp >> 16) & 0xFF
value[4] = (timestamp >> 8) & 0xFF
value[5] = timestamp & 0xFF
# version and variant
value[6] = (value[6] & 0x0F) | 0x70
value[8] = (value[8] & 0x3F) | 0x80
return value
if __name__ == "__main__":
uuid_val = uuidv7()
print(''.join(f'{byte:02x}' for byte in uuid_val))
C++
#include <array>
#include <chrono>
#include <cstdint>
#include <cstdio>
#include <random>
std::array<uint8_t, 16> uuidv7() {
// random bytes
std::random_device rd;
std::array<uint8_t, 16> random_bytes;
std::generate(random_bytes.begin(), random_bytes.end(), std::ref(rd));
std::array<uint8_t, 16> value;
std::copy(random_bytes.begin(), random_bytes.end(), value.begin());
// current timestamp in ms
auto now = std::chrono::system_clock::now();
auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(
now.time_since_epoch()
).count();
// timestamp
value[0] = (millis >> 40) & 0xFF;
value[1] = (millis >> 32) & 0xFF;
value[2] = (millis >> 24) & 0xFF;
value[3] = (millis >> 16) & 0xFF;
value[4] = (millis >> 8) & 0xFF;
value[5] = millis & 0xFF;
// version and variant
value[6] = (value[6] & 0x0F) | 0x70;
value[8] = (value[8] & 0x3F) | 0x80;
return value;
}
int main() {
auto uuid_val = uuidv7();
for (const auto& byte : uuid_val) {
printf("%02x", byte);
}
printf("\n");
return 0;
}
JavaScript
function uuidv7() {
// random bytes
const value = new Uint8Array(16);
crypto.getRandomValues(value);
// current timestamp in ms
const timestamp = BigInt(Date.now());
// timestamp
value[0] = Number((timestamp >> 40n) & 0xffn);
value[1] = Number((timestamp >> 32n) & 0xffn);
value[2] = Number((timestamp >> 24n) & 0xffn);
value[3] = Number((timestamp >> 16n) & 0xffn);
value[4] = Number((timestamp >> 8n) & 0xffn);
value[5] = Number(timestamp & 0xffn);
// version and variant
value[6] = (value[6] & 0x0f) | 0x70;
value[8] = (value[8] & 0x3f) | 0x80;
return value;
}
const uuidVal = uuidv7();
const uuidStr = Array.from(uuidVal)
.map((b) => b.toString(16).padStart(2, "0"))
.join("");
console.log(uuidStr);
UUIDv4 (完全随机或伪随机)
UUID(Universally Unique Identifier)是一个由128位构成的标识符,通常以32个十六进制数字表示,并通过破折号分为五组,形成8-4-4-4-12的格式。例如," 123e4567-e89b-12d3-a456-426655440000"。UUID v4的每个十六进制字符可取值范围为0至f。在数据库中,UUID v4可以以字符串形式或直接以16字节的二进制形式存储。
UUID v4通过完全随机或伪随机数生成器生成,确保了其高度的唯一性。据估计,生成的UUID v4样本具有3.26*10¹⁶的基数,重复概率低于0.01%。