개발/자바

Java UUID란?

피터JK 2025. 2. 8. 16:19
728x90

UUID(Universally Unique Identifier)는 전역적으로 고유한 식별자를 생성하는 방식입니다. Java에서는 java.util.UUID 클래스를 통해 UUID를 쉽게 생성할 수 있습니다.

import java.util.UUID;

public class UUIDExample {
    public static void main(String[] args) {
        UUID uuid = UUID.randomUUID(); // UUID v4 방식
        System.out.println("Generated UUID: " + uuid);
    }
}

UUID는 128비트(16바이트) 크기의 값을 가지며, 약 2¹²⁸(≈ 3.4 × 10³⁸) 개의 고유한 값을 생성할 수 있습니다. 이는 현실적으로 중복될 가능성이 거의 없는 수준입니다.


UUID는 중복될 수 있을까?

이론적으로는 UUID도 중복될 가능성이 있습니다. 하지만, 그 확률이 너무 낮아서 현실적으로 걱정할 필요가 없습니다.

1. 무작위(UUID v4) 기반 중복 가능성

UUID.randomUUID()는 UUID v4 방식을 사용하며, 랜덤 값을 기반으로 생성됩니다.

예제: 1조 개(10¹²)의 UUID를 생성했을 때 중복될 확률?

- UUID v4는 122비트 랜덤값을 포함 (나머지 6비트는 버전 정보)
- 생성 가능한 UUID 개수 = 2¹²² ≈ 5.3 × 10³⁶
- 생일 문제(Birthday Problem) 확률 계산에 따르면, 1조 개의 UUID를 생성해도 중복 확률 ≈ 10⁻¹⁸
이는 벼락 맞을 확률(10⁻⁶)보다도 훨씬 낮음

즉, UUID v4 방식은 현실적으로 중복 걱정을 하지 않아도 됩니다.

2. 특정 값을 기반으로 생성(UUID v3, v5)

  • UUID.nameUUIDFromBytes(byte[])를 사용하면, 입력값이 같으면 항상 동일한 UUID가 생성됨
  • 예를 들어, "example.com"을 기반으로 UUID를 만들면 누구든 같은 UUID를 얻게 됨
  • 해결 방법: 랜덤 UUID(v4) 또는 추가적인 고유값과 함께 사용

3. 잘못된 UUID 사용 사례

UUID 중복이 발생하는 주요 원인은 잘못된 코드 구현 때문입니다.

  • UUID 일부만 사용 → UUID.toString().substring(0, 8)처럼 일부만 사용하면 중복 위험 증가
  • 잘못된 난수 생성기 사용 → SecureRandom 대신 단순 PRNG 사용 시 위험
  • DB에서 UUID를 Shortened ID로 변환 → 해시 충돌 가능성 존재

UUID 중복 방지 방법

1. UUID v4 대신 UUID v1 사용

UUID v1은 현재 시간(타임스탬프)과 MAC 주소를 사용하여 생성됩니다.

UUID v1 직접 구현 예시:

import java.net.NetworkInterface;
import java.nio.ByteBuffer;
import java.util.Enumeration;
import java.util.Random;
import java.util.UUID;

public class UUIDv1Generator {
    private static long lastTimestamp = -1;
    private static final Random random = new Random();

    public static UUID generateUUIDv1() {
        long timestamp = System.currentTimeMillis();
        long macAddress = getMacAddress();

        if (timestamp <= lastTimestamp) {
            timestamp = ++lastTimestamp;
        } else {
            lastTimestamp = timestamp;
        }

        long mostSigBits = (timestamp << 32) | (macAddress & 0xFFFFFFFFL);
        long leastSigBits = random.nextLong();

        return new UUID(mostSigBits, leastSigBits);
    }

    private static long getMacAddress() {
        try {
            Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
            while (interfaces.hasMoreElements()) {
                byte[] mac = interfaces.nextElement().getHardwareAddress();
                if (mac != null) {
                    ByteBuffer buffer = ByteBuffer.wrap(mac);
                    return buffer.getLong();
                }
            }
        } catch (Exception ignored) { }
        return new Random().nextLong();
    }

    public static void main(String[] args) {
        UUID uuid1 = generateUUIDv1();
        System.out.println("UUID v1: " + uuid1);
    }
}

UUID v1은 시스템 시간과 MAC 주소를 사용하므로 중복 가능성이 더 낮음

2. UUID + 추가 정보 조합

UUID 자체도 고유하지만, 추가적인 정보와 함께 사용하면 중복을 더욱 방지할 수 있습니다.

UUID uuid = UUID.randomUUID();
String userSpecificUUID = uuid.toString() + "-" + System.currentTimeMillis();
System.out.println(userSpecificUUID);

📌 UUID + 타임스탬프 조합을 사용하면 사실상 중복이 불가능해짐.

3. 데이터베이스에서 UUID 중복 방지

UUID가 중복될 가능성은 매우 낮지만, 데이터베이스에서는 유니크(UNIQUE) 제약 조건을 추가하는 것이 좋습니다.

CREATE TABLE users (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    name VARCHAR(100) NOT NULL
);

📌 PostgreSQL에서는 gen_random_uuid() 함수를 사용하여 중복을 방지할 수 있습니다.


결론

 중복 가능성 비고

UUID 버전 중복 가능성 비고
UUID v1 매우 낮음 MAC 주소 + 타임스탬프 사용
UUID v3 있음 동일한 입력값이면 같은 UUID
UUID v4 극히 낮음 랜덤값 기반 (중복 확률 사실상 0)
UUID v5 있음 동일한 입력값이면 같은 UUID

현실적으로 UUID v4를 사용하면 중복 걱정 없이 사용할 수 있음
중복이 걱정된다면 UUID v1을 직접 구현하거나, 추가적인 정보(Timestamp 등)를 결합
데이터베이스에서는 UNIQUE 제약 조건을 사용하여 안전성을 확보


🎯 결론: UUID 중복 가능성은 현실적으로 무시해도 될 정도로 낮다! 

728x90