분산 시스템과 마이크로서비스 환경이 보편화되면서 UUID 생성은 백엔드 개발의 기본 소양이 되었습니다. 데이터베이스 충돌 없는 식별자가 필요한 거의 모든 상황에서 UUID는 가장 신뢰받는 선택지로 자리 잡았습니다.
UUID란 무엇이며 왜 사용하는가
UUID는 Universally Unique Identifier의 약자로, 128비트 길이의 고유 식별자를 의미합니다. 표준 표기법은 8-4-4-4-12 형식의 16진수 문자열이며, 예시로는 550e8400-e29b-41d4-a716-446655440000와 같은 형태가 됩니다.
전통적인 자동증가 정수 ID와 달리 UUID는 중앙 서버에 의존하지 않고도 충돌 가능성이 극히 낮은 식별자를 만들 수 있습니다. 이 특성 덕분에 다음과 같은 환경에서 특히 유용합니다.
- 여러 데이터베이스를 합치거나 마이그레이션해야 할 때
- 오프라인에서 먼저 ID를 생성하고 나중에 동기화하는 모바일 앱
- 마이크로서비스 간 이벤트 추적 ID로 활용할 때
- 외부에 노출해도 내부 정보가 유출되지 않아야 하는 공개 식별자
UUID 버전별 차이점 정리
UUID는 생성 방식에 따라 여러 버전이 존재합니다. 각 버전은 고유한 용도와 장단점을 가지고 있어, 상황에 맞게 선택하는 것이 중요합니다.
| 버전 | 생성 기준 | 특징 | 주 용도 |
|---|---|---|---|
| v1 | MAC 주소 + 타임스탬프 | 시간순 정렬 가능, MAC 노출 우려 | 로그 시스템 |
| v3 | MD5 해시 | 같은 입력에 항상 같은 결과 | 네임스페이스 식별 |
| v4 | 난수 기반 | 가장 널리 사용, 충돌 거의 불가능 | 일반 PK |
| v5 | SHA-1 해시 | v3보다 안전, 같은 입력에 같은 결과 | URL 기반 ID |
| v7 | 유닉스 타임스탬프 + 난수 | 시간순 정렬과 충돌 방지를 동시에 | 최신 DB PK |
실무에서는 v4가 가장 흔하지만, 데이터베이스 인덱스 효율을 고려한다면 v7이 점차 새로운 표준으로 자리 잡고 있습니다. PostgreSQL 18부터는 v7을 기본 함수로 지원할 예정입니다.
언어별 UUID 생성 방법 5가지
대부분의 프로그래밍 언어는 표준 라이브러리나 검증된 패키지를 통해 UUID 생성을 지원합니다. 자주 사용되는 언어별 코드 예시를 정리했습니다.
1. JavaScript (Node.js) - Node.js 19 이상에서는 내장 crypto.randomUUID()를 별도 패키지 없이 바로 사용할 수 있습니다.
const { randomUUID } = require('crypto');
const id = randomUUID();
2. Python - 표준 라이브러리 uuid 모듈로 모든 주요 버전을 생성할 수 있습니다.
import uuid
id_v4 = uuid.uuid4()
id_v5 = uuid.uuid5(uuid.NAMESPACE_DNS, 'example.com')
3. Java - java.util.UUID 클래스가 v3와 v4를 기본 제공합니다.
UUID id = UUID.randomUUID();
4. Go - 표준 라이브러리에는 없으므로 github.com/google/uuid 패키지를 가장 많이 사용합니다.
id := uuid.New()
5. SQL 직접 생성 - PostgreSQL은 gen_random_uuid(), MySQL 8.0은 UUID() 함수를 데이터베이스 차원에서 제공합니다.
코드를 작성하지 않고 당장 한두 개의 UUID가 필요할 때는 웹 기반 UUID 생성기를 활용하면 테스트 데이터를 빠르게 만들어볼 수 있습니다.
for i in {1..100}; do uuidgen; done 같은 명령으로 대량 생성을 손쉽게 처리할 수 있습니다.UUID 사용 시 실무 주의사항
UUID는 만능이 아닙니다. 잘못 적용하면 성능 저하나 보안 이슈로 이어질 수 있어 다음 사항을 반드시 검토해야 합니다.
- 인덱스 단편화: v4는 완전 무작위라 B-tree 인덱스에서 페이지 스플릿이 자주 발생합니다. 대용량 테이블의 PK라면 v7이나 ULID 사용을 고려하세요.
- 저장 공간: UUID는 16바이트로 4바이트 정수보다 4배 크고, 문자열로 저장하면 36바이트까지 늘어납니다. binary(16) 타입을 활용하는 편이 좋습니다.
- 가독성: 사람이 직접 다루기 어렵습니다. 로그나 디버깅용 식별자는 별도의 짧은 코드를 함께 두는 것이 효율적입니다.
- v1 사용 자제: MAC 주소가 노출되어 보안 감사 단계에서 지적될 수 있습니다.
crypto.randomBytes(32)처럼 충분한 엔트로피를 보장하는 함수를 사용해야 합니다.UUID와 자동증가 ID 비교
어떤 식별자 전략이 좋은지는 시스템의 규모와 요구사항에 따라 달라집니다. 두 방식의 장단점을 정리하면 아래와 같습니다.
| 항목 | UUID | 자동증가 ID |
|---|---|---|
| 충돌 가능성 | 사실상 없음 | 분산 환경에서 발생 |
| 저장 크기 | 16바이트 | 4~8바이트 |
| 인덱스 성능 | v4는 낮고 v7은 양호 | 매우 우수 |
| 외부 노출 | 안전 | 레코드 수 추정 가능 |
| 오프라인 생성 | 가능 | 불가능 |
결론적으로 단일 데이터베이스 환경에서는 자동증가 ID가 여전히 효율적이며, 분산 시스템이나 외부 공개가 필요한 경우에는 UUID v7이 가장 균형 잡힌 선택입니다. 시스템의 성격을 먼저 진단한 뒤, 그에 맞는 전략을 고르는 것이 중요합니다.