Trình tạo UUID v1

Tạo UUID v1 dựa trên thời gian với dấu thời gian nhúng

Định dạng

Số lượng:
Note:UUID v1 nhúng địa chỉ MAC của máy chủ và timestamp tạo, điều này gây ra lo ngại về quyền riêng tư cho hầu hết các ứng dụng hiện đại. Đối với các dự án mới, UUID v4 được khuyến nghị.

UUID v1 là gì?

UUID v1 là phiên bản UUID gốc, được chuẩn hóa trong RFC 4122 (2005). UUID v1 tạo ra các định danh duy nhất bằng cách kết hợp timestamp độ chính xác cao với địa chỉ MAC của máy chủ tạo.

Vì timestamp được nhúng vào, các giá trị UUID v1 từ cùng máy chủ tăng đơn điệu theo thời gian — làm cho chúng tự nhiên có thứ tự.

Ngày nay UUID v1 phần lớn đã bị thay thế bởi UUID v7 (có thể sắp xếp, không rò rỉ MAC) và UUID v4 (hoàn toàn ngẫu nhiên, riêng tư). UUID v1 vẫn được sử dụng trong các hệ thống như Apache Cassandra.

Cấu trúc UUID v1

Chuỗi UUID v1 như 550e8400-e29b-11d4-a716-446655440000 mã hóa sáu trường khác nhau:

TrườngKích thướcMô tả
time_low32 bitsTrường thấp 32-bit của timestamp Gregorian 60-bit (khoảng cách 100 nano giây kể từ ngày 15 tháng 10 năm 1582)
time_mid16 bitsTrường giữa 16-bit của timestamp 60-bit
time_hi_and_version16 bits12 bit trên của timestamp 60-bit cộng số phiên bản 4-bit (luôn là <code>1</code>)
clock_seq_hi_res8 bitsTrường cao 6-bit của chuỗi đồng hồ kết hợp với dấu biến thể RFC 4122 2-bit
clock_seq_low8 bits8 bit thấp hơn của chuỗi đồng hồ
node48 bitsĐịnh danh node 48-bit — thường là địa chỉ MAC của giao diện mạng tạo

Trường chuỗi đồng hồ là bộ đếm 14-bit. Nó được tăng lên mỗi khi đồng hồ hệ thống chạy lùi.

Giải mã Timestamp UUID v1

Timestamp 60-bit được phân tán qua ba trường trong UUID. Để tái tạo thời gian tạo:

  1. Trích xuất time_low (byte 0–3), time_mid (byte 4–5), và time_hi (byte 6–7, trừ nibble phiên bản)
  2. Lắp ráp lại: (time_hi &lt;&lt; 48) | (time_mid &lt;&lt; 32) | time_low
  3. Kết quả là số đếm 60-bit của khoảng cách 100 nano giây kể từ ngày 15 tháng 10 năm 1582 (epoch lịch Gregorian)
  4. Trừ độ lệch Gregorian-sang-Unix: 122.192.928.000.000.000
  5. Chia cho 10.000 để chuyển đổi khoảng cách 100 nano giây sang mili giây
  6. Sử dụng kết quả làm timestamp mili giây Unix để tạo đối tượng Date
  7. Định dạng thành ISO 8601 để xuất ra dạng con người đọc được

Độ chính xác timestamp là 100 nano giây — tinh hơn nhiều so với độ chính xác mili giây của UUID v7.

Lo ngại Quyền riêng tư

Nhược điểm đáng kể nhất của UUID v1 là nó nhúng địa chỉ MAC của máy chủ tạo vào trường node.

Kẻ tấn công có được UUID v1 có thể xác định: (1) thời điểm tạo ID gần đúng, (2) địa chỉ MAC của máy chủ tạo, và (3) bằng cách phân tích nhiều UUID, tốc độ tạo ID.

Vì lý do này, UUID v1 không bao giờ nên được sử dụng làm định danh hướng công khai trừ khi bạn thoải mái khi tiết lộ thông tin này.

Khi nào UUID v1 Vẫn Phù hợp

Khóa chính Apache Cassandra
Cassandra sử dụng UUID v1 (thông qua loại TimeUUID) như một mẫu thiết kế cốt lõi.
Hệ thống phân tán cũ
Các hệ thống được xây dựng trước khi UUID v7 tồn tại (trước 2024) dựa trên UUID theo thứ tự timestamp.
Nhật ký kiểm toán và sự kiện
Khi danh tính máy chủ tạo được biết và tin cậy, việc nhúng địa chỉ MAC có thể cung cấp khả năng truy vết thêm.
Định danh nội bộ
ID không bao giờ được lộ ra ngoài hệ thống nội bộ được kiểm soát.
Truy vấn phạm vi thời gian không có cột timestamp riêng
Timestamp nhúng có thể được giải mã để lọc hàng theo thời gian tạo.
Khả năng tương tác với các bộ tạo UUID v1 cũ
Khi nhận hoặc xử lý các giá trị UUID v1 từ các hệ thống bên ngoài.

UUID v1 so với UUID v7

UUID v7 là người kế thừa hiện đại của UUID v1 cho các định danh theo thứ tự thời gian:

Khía cạnhUUID v1UUID v7
Epoch / Cơ sở Thời gianEpoch Gregorian (15 tháng 10 năm 1582)Epoch Unix (1 tháng 1 năm 1970)
Độ chính xác100 nano giây1 mili giây
Định danh NodeĐịa chỉ MAC (rò rỉ danh tính máy chủ)Ngẫu nhiên (riêng tư)
Quyền riêng tưRò rỉ địa chỉ MAC và timestamp tạoKhông nhúng thông tin máy chủ
Hiệu suất chỉ mục DBTốt — tuần tự theo máy chủXuất sắc — k-sortable trên tất cả bộ tạo
Tiêu chuẩnRFC 4122 (2005)RFC 9562 (2024)

Đối với các dự án mới, UUID v7 là sự thay thế được khuyến nghị cho UUID v1.

Ví dụ Mã

Tạo UUID v1 không có sẵn gốc trong trình duyệt hoặc Node.js. Sử dụng gói npm uuid:

JavaScript (browser)
// Generate a UUID v1 using the Web Crypto API
function generateUuidV1() {
  const buf = new Uint8Array(16)
  crypto.getRandomValues(buf)

  const ms = BigInt(Date.now())
  const gregorianOffset = 122192928000000000n
  const t = ms * 10000n + gregorianOffset

  const tLow   = Number(t & 0xFFFFFFFFn)
  const tMid   = Number((t >> 32n) & 0xFFFFn)
  const tHiVer = Number((t >> 48n) & 0x0FFFn) | 0x1000  // version 1

  const clockSeq    = (buf[8] & 0x3F) | 0x80  // variant 10xxxxxx
  const clockSeqLow = buf[9]

  const hex  = (n, pad) => n.toString(16).padStart(pad, '0')
  const node = [...buf.slice(10)].map(b => b.toString(16).padStart(2, '0')).join('')

  return `${hex(tLow,8)}-${hex(tMid,4)}-${hex(tHiVer,4)}-${hex(clockSeq,2)}${hex(clockSeqLow,2)}-${node}`
}

// Extract the embedded timestamp from a UUID v1
function extractTimestamp(uuid) {
  const parts = uuid.split('-')
  const tHex = parts[2].slice(1) + parts[1] + parts[0]
  const t = BigInt('0x' + tHex)
  const ms = (t - 122192928000000000n) / 10000n
  return new Date(Number(ms))
}

const id = generateUuidV1()
console.log(id)                      // e.g. "1eb5e8b0-6b4d-11ee-9c45-a1f2b3c4d5e6"
console.log(extractTimestamp(id))    // e.g. 2023-10-15T12:34:56.789Z
Python
import uuid
from datetime import datetime, timezone

# Generate UUID v1 (uses MAC address by default)
uid = uuid.uuid1()
print(uid)

# Extract embedded timestamp
# uuid.time is 100-ns intervals since Oct 15, 1582
GREGORIAN_OFFSET = 122192928000000000  # 100-ns intervals
ts_100ns = uid.time
ts_ms = (ts_100ns - GREGORIAN_OFFSET) // 10000
dt = datetime.fromtimestamp(ts_ms / 1000, tz=timezone.utc)
print(dt.isoformat())   # e.g. "2023-10-15T12:34:56.789000+00:00"
Go
package main

import (
    "fmt"
    "time"

    "github.com/google/uuid"  // go get github.com/google/uuid
)

func main() {
    id, _ := uuid.NewUUID()  // UUID v1
    fmt.Println(id)

    // Extract timestamp from UUID v1
    // uuid.Time is 100-ns ticks since Oct 15, 1582
    t := id.Time()
    sec  := int64(t)/1e7 - 12219292800  // convert to Unix seconds
    nsec := (int64(t) % 1e7) * 100
    ts   := time.Unix(sec, nsec).UTC()
    fmt.Println(ts.Format(time.RFC3339Nano))
}

Câu hỏi Thường gặp

Tôi có thể giải mã timestamp từ UUID v1 không?
Có. Timestamp tạo có thể được khôi phục hoàn toàn từ chuỗi UUID v1.
Địa chỉ MAC có luôn xuất hiện trong UUID v1 không?
Không nhất thiết. RFC 4122 cho phép các triển khai thay thế giá trị 48-bit được tạo ngẫu nhiên cho địa chỉ MAC.
Tại sao timestamp UUID v1 sử dụng 1582 làm epoch?
Cải cách lịch Gregorian có hiệu lực vào ngày 15 tháng 10 năm 1582. Timestamp UUID v1 được định nghĩa tương đối với ngày này.
UUID v1 so với UUID v7 — khi nào tôi vẫn nên dùng v1?
Lý do chính để sử dụng UUID v1 ngày nay là khả năng tương thích với các hệ thống hiện có — đặc biệt là Apache Cassandra.
Các giá trị UUID v1 có thể va chạm không?
Về lý thuyết, hai giá trị UUID v1 có thể va chạm nếu cùng địa chỉ MAC tạo hai UUID trong cùng khoảng 100 nano giây.