본문으로 건너뛰기
wooncloud

분산 시스템에서 쓰는 ID 형식 총정리 — UUID, ULID, Snowflake, NanoID 비교

신규 프로젝트는 표준이고 시간순 정렬되는 UUID v7 부터 검토하고, 라이브러리·DB 지원이 부족하면 더 짧은 ULID 가 합리적 대안이며, 외부 노출 ID 는 Auto-increment 를 피해야 합니다.

·10 min read·— views··

데이터베이스에 새 레코드를 만들 때 가장 먼저 고민하는 것. "식별자(ID)를 뭘로 쓸까?"

옛날엔 단순했습니다. AUTO_INCREMENT INT 하나로 끝이었습니다. 그런데 분산 시스템, 마이크로서비스, 클라이언트 사이드 ID 생성이 일반화되면서 선택지가 폭발했습니다. 이 글에서는 실무에서 자주 마주치는 ID 형식을 정리합니다.

한눈에 보는 비교표

형식길이정렬충돌 위험URL Safe보안비고
Auto-increment INT4-8 byte✅DB 단일✅❌ 예측 가능단일 DB 최적, 분산 X
UUID v136자⚠ 부분매우 낮음✅⚠ MAC 노출잘 안 씀
UUID v436자❌사실상 0✅✅ 완전 랜덤가장 일반적
UUID v736자✅매우 낮음✅✅RFC 9562 (2024) 차세대 표준
ULID26자✅매우 낮음✅✅UUID v7 의 전신
KSUID27자✅매우 낮음✅✅Segment 의 시간정렬 ID (ULID 와 별개 설계)
Snowflake64bit✅노드 ID 충돌 시✅❌ 예측 가능Twitter, Instagram
NanoID21자❌매우 낮음✅✅짧고 빠름
CUID224자❌매우 낮음✅✅해시 기반
Mongo ObjectId24자 hex✅사실상 0✅⚠ 생성 시각 노출MongoDB 기본

Auto-increment INTEGER

가장 오래된 방식입니다. DB 가 자동으로 1, 2, 3... 부여합니다.

  • 장점: 가장 짧음 (4-8 byte), 인덱스 효율 최강
  • 단점:
    • 분산 환경에서 만들 수 없습니다 (반드시 DB 에 INSERT 후 받아야 합니다)
    • URL 에 노출 시 enumeration 공격에 취약합니다 (/orders/1, /orders/2 식으로 다음 ID 추측 가능합니다)
    • 총 주문 수·성장률 같은 비즈니스 지표가 그대로 노출됩니다

언제 쓰나요? 내부 시스템, 외부 노출 없는 단일 DB 환경.

UUID v4 (랜덤)

지금까지도 가장 흔히 쓰이는 표준입니다 (RFC 4122).

550e8400-e29b-41d4-a716-446655440000
  • 장점:
    • 어디서나 생성 가능합니다 (DB 호출 X)
    • 122bit 랜덤 → 충돌 사실상 0
    • 표준이라 모든 언어/DB 가 지원합니다
  • 단점:
    • 36자로 깁니다
    • 정렬 안 됨 → DB 인덱스에서 페이지 캐시 미스가 증가합니다
    • 랜덤하게 삽입되니 B-tree fragmentation 이 발생합니다

PostgreSQL 에서는 gen_random_uuid() 로 생성합니다.

UUID v7 (2024년 표준화)

UUID v4 의 단점인 인덱스 fragmentation 을 해결한 차세대 표준입니다.

018e7eb3-0c5f-7d1a-a3e3-66c4d1a3a5b1
└──────timestamp─────┘└─────random─────┘

앞 48bit 가 milliseconds timestamp → 시간순 정렬 가능합니다.

  • 장점:
    • UUID 형식 호환 (36자, hex)
    • 정렬 가능 → 인덱스 효율 ↑
    • RFC 9562 표준
    • PostgreSQL 18+ 가 uuidv7() 을 native 제공 (17 이하는 pg_uuidv7 확장이나 애플리케이션에서 생성). MySQL 은 9.x 기준 v7 생성 함수가 없다
  • 단점:
    • 아직 모든 라이브러리가 native 지원하지 않습니다
    • 일부 환경에선 수동 구현이 필요합니다

신규 프로젝트라면 가장 유력한 후보입니다.

ULID

UUID v7 의 영감이 된, 더 짧은 형식입니다 (2016년 등장).

01ARZ3NDEKTSV4RRFFQ69G5FAV
└─timestamp─┘└─random───────┘
  • 장점:
    • 26자 (UUID 보다 짧습니다)
    • Crockford Base32 (대소문자 모호한 글자 제거 — I, L, O, U 제외)
    • 시간순 정렬
    • 사람 눈으로 비교가 쉽습니다
  • 단점:
    • RFC 표준이 아닙니다
    • 라이브러리 품질이 들쭉날쭉합니다
    • 같은 ms 안에서 monotonic 보장하려면 별도 옵션이 필요합니다 (monotonicFactory)

prefix 패턴과 잘 어울립니다. user_01ARZ3..., order_01ARZ4... 같은 식입니다.

KSUID (Segment, 2017)

ULID 와 매우 유사한 형식입니다.

  • 장점: 4 byte 초 단위 timestamp + 16 byte 랜덤, base62 인코딩 (숫자+영문 대소문자)
  • 단점: ULID 와 거의 동일 영역입니다. 사용자 수가 적습니다

Snowflake (Twitter, 2010)

대용량 분산 시스템의 대표 ID 형식입니다.

| 1bit |    41bit timestamp    | 10bit machine | 12bit sequence |
  • 장점:
    • 64bit 정수 → BIGINT 컬럼에 그대로 저장
    • 머신당 밀리초당 4096개 생성 (= 초당 약 409만 개)
    • 정렬·인덱스 효율 우수
  • 단점:
    • machine ID 사전 할당이 필요합니다 (Zookeeper 등)
    • 예측 가능합니다 (보안성 ❌)
    • 시계 동기화 (clock skew) 이슈

언제 쓰나요? Twitter, Discord, Instagram 처럼 초당 수천~수만 ID 가 필요한 시스템.

NanoID

URL 친화적인 짧은 ID입니다.

V1StGXR8_Z5jdHi6B-myT
  • 장점:
    • 21자 (기본, 조절 가능)
    • UUID v4 대비 2배 빠른 생성
    • URL alphabet
  • 단점: 정렬 불가, 표준 아님

언제 쓰나요? URL 단축, 슬러그, 공개 식별자.

CUID2 (2022)

해시 기반의 신형 ID입니다.

  • 장점:
    • 외부에서 fingerprint·추측이 매우 어렵습니다
    • Horizontal scalability
    • Session 무관
  • 단점:
    • 정렬 불가합니다
    • 생성 시간이 UUID 보다 느립니다
    • 검증 비용

언제 쓰나요? 보안이 핵심이고 fingerprint 저항이 필요한 경우.

MongoDB ObjectId

MongoDB 의 기본 ID입니다.

| 4 byte timestamp | 5 byte random (프로세스당 1회 생성) | 3 byte counter |
  • 장점: 12 byte (24자 hex), 자동 정렬, MongoDB 가 자동 부여
  • 단점: 초 단위 생성 시각이 노출되고 같은 프로세스에서 만든 ID 를 묶어볼 수 있음(MAC·호스트 역산은 불가), MongoDB 외 환경에선 표준 아님

인덱스 효율은 왜 정렬이 중요한가?

UUID v4 처럼 랜덤한 ID 를 B-tree 인덱스에 삽입하면 다음 문제가 생깁니다.

  1. 새 ID 가 인덱스 트리의 랜덤한 위치 에 들어갑니다
  2. 디스크의 여러 페이지를 동시에 갱신해야 합니다
  3. 페이지 캐시 미스 → I/O 가 폭증합니다
  4. B-tree 페이지 분할 (page split) 이 빈번합니다

반면 UUID v7, ULID, Snowflake 처럼 시간순으로 증가하는 ID 는 항상 인덱스 트리의 끝에 추가되니, 직전에 갱신한 페이지를 그대로 쓰면 됩니다. 수십 배의 쓰기 성능 차이 가 날 수 있습니다.

선택 가이드

상황추천
표준 따라가고 시간순 정렬 원함UUID v7
짧은 ID + 시간순 + URL prefix 디자인ULID
표준 1순위, 정렬 무관UUID v4
URL 단축 / 슬러그NanoID
Fingerprint 저항이 핵심CUID2
고볼륨 분산 시스템 (Twitter/Discord 급)Snowflake
내부 단일 DB, 외부 노출 없음Auto-increment INT
MongoDBObjectId

마무리

ID 형식 선택은 요구사항에 따라 다릅니다. 단순한 정답은 없습니다. 핵심 질문은 세 가지입니다.

  1. 분산 환경인가요? → 분산이면 INT 제외
  2. 외부에 노출되나요? → 노출되면 예측 가능한 형식 제외 (INT, Snowflake)
  3. 시간순 정렬이 필요한가요? → 필요하면 UUID v7, ULID, Snowflake

새 프로젝트라면 UUID v7 부터 검토해 봅시다. 표준이고, 정렬 가능하고, 생태계도 빠르게 따라오고 있습니다. 라이브러리·DB 가 아직 준비 안 된 환경이라면 ULID 가 합리적 대안입니다.

ID 는 한번 정하면 바꾸기 어렵습니다. 시작할 때 신중하게 골라야 합니다.