Post

ID 채번 전략(feat. snowflake ID vs UUIDv7)

랜덤 ID전략에 시간을 더했다

ID 채번(고유 식별자 생성) 전략

기본적인 ID 채번에 대해서 설명하며 밑에서 snowflake ID와 UUIDv7에 대해 설명합니다.

아래부분에서 snowflake ID와 UUIDv7에 대해서 다룹니다.

ID 채번이란?

ID 채번(Sequence Generation)은 데이터베이스나 시스템에서 유일한 식별자를 생성하는 방식을 의미합니다.
고유한 ID는 데이터 무결성을 유지하고, 중복을 방지하며, 시스템 간 연계를 가능하게 합니다.

ID 생성 방식은 크게 중앙 집중식 방식과 분산 방식으로 나눌 수 있습니다.


ID 채번 전략 종류

자동 증가 (Auto Increment)

데이터베이스가 자동으로 1씩 증가하는 정수를 ID로 할당하는 방식입니다.

  • 장점
    • 간단하고 직관적
    • 정렬이 용이하여 인덱스 효율이 높음
  • 단점
    • 분산 시스템에서 충돌 가능 → 하나의 DB 서버에서만 유효
    • 샤딩(Sharding)과 병렬 처리 어려움
  • 사용 사례: 단일 데이터베이스를 사용하는 서비스 (ex: MySQL, PostgreSQL의 AUTO_INCREMENT, SERIAL)
1
2
3
4
CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    name VARCHAR(50)
);

UUID v4(Universally Unique Identifier)

128비트 길이의 랜덤 문자열을 사용하여 전역적으로 유일한 ID를 생성하는 방식입니다.

  • 구조 : | 48비트 timestamp(ms) | 16비트 version | 64비트 랜덤 값 |
  • 예시 : 017F22E0-685D-412F-8283-DF738527250F => 412F에서 “4”이 UUIDv4를 의미

가운데 highlight는 버전을 의미함. 일반적인 uuid는 v4이므로 4로 시작!

  • 장점
    • 분산 시스템에서 중복 가능성이 거의 없음
    • 중앙 서버 없이도 ID 생성 가능
  • 단점
    • 길이가 길어 인덱싱 성능 저하
    • 정렬이 불가능하여 조회 속도 저하
  • 사용 사례: 분산 환경, 마이크로서비스, 블록체인 (ex: Java의 UUID.randomUUID())

UUID v7 (RFC 9562)

UUID v4의 단점인 시간 순서 정렬의 개념을 포함하였습니다.

  • 구조 : | 48비트 timestamp(ms) | 16비트 version | 64비트 랜덤 값 |
  • 예시 : 017F22E0-685D-712F-8283-DF738527250F => 712F에서 “7”이 UUIDv4를 의미

Unix timestamp(밀리초)를 포함하여 생성되므로 시간 순서대로 정렬할 수 있습니다.

  • 사용 사례: 분산환경, 특정 노드 정보 없이도 정렬 가능한 ID가 필요한 경우(ex: API Gateway, 블록체인, 로그 시스템)

Snowflake ID

Twitter에서 개발한 분산 환경에서 고유한 ID를 생성하는 알고리즘으로, 64비트 정수(Long) 값을 사용합니다.

  • 구조 : | 41비트 timestamp(ms) | 10비트 데이터센터 ID | 12비트 시퀀스 번호 |
  • 예시 : 1457984928538740736

약 이론상 timestamp는 약 69년간 사용 가능하며 데이터센터 ID는 최대 1024개, 12비트 시퀀스는 1ms당 4096개의 ID 생성 가능합니다.

  • 장점
    • 시간 순 정렬 가능
    • 성능이 뛰어나고, 초당 수백만 개의 ID 생성 가능
    • 분산 시스템에서도 충돌 없음
  • 단점
    • 서버 시간 동기화 필요
    • 비트 길이 제한 (약 69년 이후 ID 초과 발생 가능)
  • 사용 사례: 트위터 트윗 ID, 대규모 분산 시스템 (ex: Kafka 메시지 ID)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class SnowflakeIdGenerator(private val workerId: Long) {
    private val epoch = 1609459200000L
    private var sequence = 0L
    private var lastTimestamp = -1L

    @Synchronized
    fun nextId(): Long {
        var timestamp = System.currentTimeMillis()
        if (timestamp == lastTimestamp) {
            sequence = (sequence + 1) and 4095L
            if (sequence == 0L) {
                while (timestamp <= lastTimestamp) {
                    timestamp = System.currentTimeMillis()
                }
            }
        } else {
            sequence = 0L
        }
        lastTimestamp = timestamp
        return ((timestamp - epoch) shl 22) or (workerId shl 12) or sequence
    }
}

fun main() {
    val generator = SnowflakeIdGenerator(workerId = 1)
    println(generator.nextId())
}

데이터베이스 Sequence

데이터베이스에서 자체적으로 제공하는 ID 생성 기능으로, 자동 증가(Auto Increment)보다 유연한 제어가 가능합니다.

  • 장점
    • 다중 서버에서도 동작 가능
    • 특정 규칙을 기반으로 커스터마이징 가능
  • 단점
    • 중앙 집중식 관리가 필요 (병목 현상 발생 가능)
  • 사용 사례: Oracle, PostgreSQL 등 (ex: 주문 번호, 회원 번호)
    1
    
    CREATE SEQUENCE user_id_seq START WITH 1 INCREMENT BY 1;
    

데이터 조합 (Combination ID)

시간 정보 + 서버 ID + 시퀀스 번호 등의 조합으로 유니크한 ID를 생성하는 방식입니다.

  • 장점
    • 정렬 가능 (시간 기반)
    • 특정 도메인에 맞게 조정 가능
  • 단점
    • 설계가 복잡할 수 있음
  • 사용 사례: 쇼핑몰 주문 번호 (ex: YYYYMMDD-서버ID-시퀀스)
1
2
3
4
5
6
7
8
9
10
fun generateOrderId(): String {
    val date = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"))
    val serverId = 1 // 서버마다 다르게 설정
    val sequence = Random.nextInt(1000, 9999) // 임의의 4자리 숫자
    return "$date-$serverId-$sequence"
}

fun main() {
    println(generateOrderId()) // 예: 20250208-1-1234
}

UUID v7 vs. Snowflake ID 비교

분산 환경에서는 여러 서버에서 동시에 고유한 ID를 생성해야 하는 상황이 빈번하게 발생합니다.

이러한 경우, 중복되지 않는 고유 키를 생성하는 동시에 정렬이 가능한 방식이 필요합니다.

기존의 UUID v4는 랜덤성이 강해 충돌 확률이 낮지만, 정렬이 불가능하여 데이터베이스의 인덱싱 성능을 저하시킵니다.

이에 반해 Snowflake IDUUID v7시간 기반 정렬이 가능하면서도 분산 환경에서 중복되지 않는 ID를 생성할 수 있는 방식입니다.

비교 항목UUID v7Snowflake ID
ID 길이128비트 (16바이트)64비트 (8바이트)
시간 기반(Unix timestamp 기반)(Unix timestamp 기반)
정렬 가능(시간 순 정렬 가능)(시간 순 정렬 가능)
고유성충돌 가능성이 매우 낮음노드, 시퀀스 ID로 충돌 방지
분산 환경글로벌 고유 ID 생성 가능데이터센터, 노드 단위 ID 생성
성능길이가 길어 저장/비교 성능이 낮음64비트로 연산이 효율적
구조의 단순성단순한 구조 (시간 + 랜덤 값)복잡한 구조 (시간 + 노드ID + 시퀀스)

UUID v7 vs. Snowflake ID - 어떤 걸 써야 할까?

상황UUID v7 선택Snowflake ID 선택
글로벌 고유 ID 필요(랜덤성 포함)(노드 ID 필요)
시간순 정렬 필요(시간 기반)(시간 기반)
고성능 (저장/조회 최적화)(128비트)(64비트)
노드/데이터센터 기반 운영 (노드 ID 활용)
랜덤성이 필요한 경우 (순차적)
데이터 크기 최적화(길이가 김)(64비트로 작음)

결론

  • UUID v7은 완벽한 글로벌 유니크 ID를 보장하면서도 시간 순 정렬이 가능하지만, 길이가 길어 데이터베이스 인덱싱 성능이 떨어질 수 있음
  • Snowflake ID는 정수 기반 ID로 성능이 뛰어나고 시간 순 정렬이 가능하지만, 노드 ID와 시퀀스 관리가 필요
  • 분산 환경, 충돌 방지가 중요한 경우 -> UUID v7
  • 고성능, 데이터센터 기반 배포 -> Snowflake ID

데이터 저장 공간이 중요하고 성능 최적화가 필요하면 Snowflake ID, 글로벌 고유성 및 범용적이고 안전성을 보장하려면 UUID v7이 더 적합합니다.

[출처]

  • https://keeplearning.dev/twitter-snowflake-approach-is-cool-3156f78017cb
This post is licensed under CC BY 4.0 by the author.