분산 시스템에서 쓰는 ID 형식 총정리 — UUID, ULID, Snowflake, NanoID 비교
분산 시스템 환경에서 요구사항에 맞는 최적의 식별자를 선택할 수 있도록 UUID v7, ULID, Snowflake, NanoID 등 주요 ID 형식의 특징과 장단점을 비교하고 상황별 선택 가이드를 제시함
데이터베이스에 새 레코드를 만들 때 가장 먼저 고민하는 것. "식별자(ID)를 뭘로 쓸까?"
옛날엔 단순했다. AUTO_INCREMENT INT 하나로 끝. 그런데 분산 시스템, 마이크로서비스, 클라이언트 사이드 ID 생성이 일반화되면서 선택지가 폭발했다. 이 글에서는 실무에서 자주 마주치는 ID 형식을 정리한다.
한눈에 보는 비교표
| 형식 | 길이 | 정렬 | 충돌 위험 | URL Safe | 보안 | 비고 |
|---|---|---|---|---|---|---|
| Auto-increment INT | 4-8 byte | ✅ | DB 단일 | ✅ | ❌ 예측 가능 | 단일 DB 최적, 분산 X |
| UUID v1 | 36자 | ⚠ 부분 | 매우 낮음 | ✅ | ⚠ MAC 노출 | 잘 안 씀 |
| UUID v4 | 36자 | ❌ | 사실상 0 | ✅ | ✅ 완전 랜덤 | 가장 일반적 |
| UUID v7 | 36자 | ✅ | 매우 낮음 | ✅ | ✅ | RFC 9562 (2024) 차세대 표준 |
| ULID | 26자 | ✅ | 매우 낮음 | ✅ | ✅ | UUID v7 의 전신 |
| KSUID | 27자 | ✅ | 매우 낮음 | ✅ | ✅ | Segment 가 만든 ULID 변형 |
| Snowflake | 64bit | ✅ | 노드 ID 충돌 시 | ✅ | ❌ 예측 가능 | Twitter, Instagram |
| NanoID | 21자 | ❌ | 매우 낮음 | ✅ | ✅ | 짧고 빠름 |
| CUID2 | 24자 | ❌ | 매우 낮음 | ✅ | ✅ | 해시 기반 |
| Mongo ObjectId | 24자 hex | ✅ | 사실상 0 | ✅ | ⚠ machine ID 추론 | 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 17+, MySQL 9+ native 지원
- 단점:
- 아직 모든 라이브러리가 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 ID/머신 생성
- 정렬·인덱스 효율 우수
- 64bit 정수 →
- 단점:
- 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 machine | 3 byte counter |
- 장점: 12 byte (24자 hex), 자동 정렬, MongoDB 가 자동 부여
- 단점: machine ID 노출로 약간의 정보 누설, MongoDB 외 환경에선 표준 아님
인덱스 효율은 왜 정렬이 중요한가?
UUID v4 처럼 랜덤한 ID 를 B-tree 인덱스에 삽입하면 다음 문제가 생긴다.
- 새 ID 가 인덱스 트리의 랜덤한 위치 에 들어감
- 디스크의 여러 페이지를 동시에 갱신해야 함
- 페이지 캐시 미스 → I/O 폭증
- 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 |
| MongoDB | ObjectId |
마무리
ID 형식 선택은 요구사항에 따라 다르다. 단순한 정답은 없다. 핵심 질문은 세 가지다.
- 분산 환경인가? → 분산이면 INT 제외
- 외부에 노출되는가? → 노출되면 예측 가능한 형식 제외 (INT, Snowflake)
- 시간순 정렬이 필요한가? → 필요하면 UUID v7, ULID, Snowflake
새 프로젝트라면 UUID v7 부터 검토하자. 표준이고, 정렬 가능하고, 생태계도 빠르게 따라오고 있다. 라이브러리·DB 가 아직 준비 안 된 환경이라면 ULID 가 합리적 대안이다.
ID 는 한번 정하면 바꾸기 어렵다. 시작할 때 신중하게 고르자.