UUID v7 을 구현하고 싶을 때에 필요한 요점만을 정리한다.
이 기사에서는, UUID v7 의 비트 구성, version/variant 의 세우는 방법, JavaScript·Go·Shell에서의 최소 구현을 차례로 확인할 수 있도록 했다.
UUID v7의 요점
UUID v7 는 128 비트로, 선두에 밀리 세컨드 타임 스탬프를 갖는다.
| 필드 | 비트 수 | 역할 |
|---|---|---|
timestamp | 48 | 유닉스 타임(ms) |
ver | 4 | 0111(v7) |
rand_a | 12 | 랜덤 값 |
var | 2 | 10(variant) |
rand_b | 62 | 랜덤 값 |
이 구성에 의해, 생성 시각순으로 대략 정렬하기 쉬운 ID를 만들 수 있다.
구현시 공통 절차
- 먼저 16바이트를 난수로 채우기
- 처음 6바이트를 현재 시간(밀리초)으로 덮어쓰기
value[6]의 상위 4비트에0x7(version)을 설정한다value[8]의 상위 2비트에10(variant)를 설정한다
JavaScript / TypeScript 구현 예
function uuidV7Bytes(): Uint8Array { const value = new Uint8Array(16); crypto.getRandomValues(value);
const timestamp = BigInt(Date.now()); 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);
value[6] = (value[6] & 0x0f) | 0x70; value[8] = (value[8] & 0x3f) | 0x80;
return value;}Go 구현 예
package main
import ( "crypto/rand" "fmt" "time")
func uuidV7() ([16]byte, error) { var value [16]byte if _, err := rand.Read(value[:]); err != nil { return value, err }
timestamp := uint64(time.Now().UnixMilli()) value[0] = byte(timestamp >> 40) value[1] = byte(timestamp >> 32) value[2] = byte(timestamp >> 24) value[3] = byte(timestamp >> 16) value[4] = byte(timestamp >> 8) value[5] = byte(timestamp)
value[6] = (value[6] & 0x0F) | 0x70 value[8] = (value[8] & 0x3F) | 0x80
return value, nil}
func main() { id, _ := uuidV7() fmt.Printf("%x\n", id)}Shell Script 구현 예
#!/bin/sh
uuid_v7() { timestamp=$(date +%s)000 timestamp_hi=$((timestamp >> 16)) timestamp_lo=$((timestamp & 0xFFFF))
rand_a=0x$(LC_ALL=C tr -dc '0-9a-f' < /dev/urandom | head -c4) ver_rand_a=$((0x7000 | (0x0FFF & rand_a)))
rand_b_hi=0x$(LC_ALL=C tr -dc '0-9a-f' < /dev/urandom | head -c4) var_rand_hi=$((0x8000 | (0x3FFF & rand_b_hi))) rand_b_lo=$(LC_ALL=C tr -dc '0-9a-f' < /dev/urandom | head -c12)
printf "%08x-%04x-%04x-%04x-%s\n" \ "$timestamp_hi" "$timestamp_lo" "$ver_rand_a" "$var_rand_hi" "$rand_b_lo"}
uuid_v7POSIX date 에서는 밀리 세컨드를 직접 취급할 수 없기 때문에, 구현 환경에 따라서 취득 방법의 조정이 필요하게 된다.
구현 체크 항목
- 동일 밀리초 내에서 대량 생성하는 경우의 충돌 리스크를 평가한다
- 포맷(하이픈 첨부 문자열 or 16바이트)을 이용측에서 통일한다
- DB의 인덱스 전략(시계열 정렬 전제)를 먼저 결정한다
관련 링크(사이트 내)
참고 자료(외부)
-RFC 9562: UUIDs -MDN: Crypto.getRandomValues() -Go標準ライブラリ: crypto/rand
요약
UUID v7의 구현은, 어느 언어에서도 「타임스탬프 임베디드 + version/variant 의 비트 조작」이 중심이 된다.
요구 사항에 따라 기존 라이브러리를 사용할지 최소 구현을 내제할지를 선택하면 된다.
hsb.horse