UUID(Universally Unique Identifier) 버전과 사용법

2025. 8. 10. 17:53·보안
728x90
반응형

전 세계적으로 유일한 식별자를 생성하기 위한 표준 형식입니다.
업무에 적용해보자면, “다른 시스템과 충돌 없이 고유한 ID를 만들 수 있는 규격”입니다.


UUID는?

분산환경에 걸쳐 ID 충돌 없이 식별자를 생성하기 위해 나타났습니다. (멀티 스레드, 멀티 프로세스 등등)
특징으로는 126비트(16바이트)의 길이로 표기되며 32개의 16진수와 하이픈(-)의 조합 표현됩니다.

  • 예) 12341234-1234-1234-1234-123412341234
    특성상 전역적으로도 고유성을 띔으로 중앙 서버 없이도 가기 시스템이 독립적으로 ID 생성이 가능하게 되었습니다.
    대표적으로 DB PK, 분산 시스템 메시지 ID, 세션 토큰, 객체 식별자 등 다양하게 사용됩니다.

UUID 버전이 있는데…

버전별 생성 방식이 다름으로 레거시를 조심합시다.
RFC 4122 표준에서 정의된 대표 버전과 최근 채택된 v6, v7을 다음과 같이 정리했습니다.

버전 생성 방식 특징과 사용 용도
v1 시간(60비트) + MAC 주소(48비트) + 시퀀스 시간 순 정렬 가능, 하드웨어 주소 노출 위험 있음
로그·이벤트 타임라인, 순차 PK
v2 v1 + POSIX UID/GID 거의 사용되지 않음, DCE Security 전용

오래된 DCE 시스템
v3 네임스페이스 + MD5 해시 같은 입력 → 같은 UUID, 재현 가능

URL, 도메인 기반 ID
v4 난수 기반 (122비트 랜덤) 단순, 충돌 확률 매우 낮음

범용 ID, 세션 토큰
v5 네임스페이스 + SHA-1 해시 v3과 동일하지만 SHA-1 사용

URL, 도메인 기반 ID
v6 v1 변형 (시간 필드를 비트 순서 변경해 정렬 친화성↑) DB 인덱스·정렬 최적화, MAC 주소 포함 가능
v7 Unix Epoch 타임스탬프(밀리초) + 랜덤 비트 가독성·정렬성↑, MAC 주소 사용 안 함, 충돌 방지

로그, 타임라인, PK 생성 (v4 대체 후보)

UUID의 역사에 대해 조사한 내용

  • 1980년대 초반
    UUID 개념은 Apollo Computer의 네트워크 OS에서 처음 사용됨. 당시에는 “NCS Identifier”라는 이름.
  • 1988년
    DCE(Distributed Computing Environment) 표준에 채택. 이 시기부터 “UUID”라는 용어 사용.
  • 1997년
    UUID 규격이 ISO/IEC 11578 표준으로 지정됨. v1 형식(시간+MAC) 기반.
  • 2005년
    RFC 4122가 발표되며 현재 우리가 사용하는 UUID 형식(버전 1~5) 정의.
  • 최근
    • UUIDv4 (랜덤 기반) 사용이 가장 보편적.
    • UUIDv7 같은 시간 기반 + 랜덤 혼합 규격이 IETF에서 논의 중(정렬성 + 난수 안정성 확보 목적).
    • 대규모 분산 시스템에서는 ULID, KSUID 등 더 정렬 친화적인 대안도 등장.

많이 사용되는 UUID의 Bit 구성을 보면

 

  • 노랑 → 시간 정보(타임스탭프 기반)
  • 보라 → 버전 비트(UUID 버전 식별)
  • 파랑 → variant나 Clock Sequence
  • 연두 → MAC 주소나 랜덤 비트

이걸 보면

  • MSB는 주로 시간, 버전
  • LSB는 랜덤, MAC
    쪽에 위치한다는 걸 직관적으로 확인할 수 있습니다.

그래서 어느 버전을 사용할까?

v1을 보면 시간순으로 정렬 가능하지만, 비트 순서가 DB 인덱스에 친화적이지 않으며 MAC 주소 노출 문제가 있습니다.
V4는 순서성이 전혀 없어 인덱스 성능이 떨어집니다.
v6은 v1의 시간 기반 구조를 재배열하여 정렬성과 성능 최적화를 하였습니다.
v7은 v4 + 시간 순서성을 결합해 MAC 주소 없이 안전하게 정렬 가능합니다.

자바의 UUID는 v4를 사용하고 있습니다. 앱 내부적으로 사용하고 시간과 무관한 값이면 UUID v4를 사용해도 됩니다.
다만, 시간과 정렬 최적화가 필요하다면 UUID v7을 사용하는 것이 바람직하다고 할 수 있습니다.

v6, v7의 시간 기준은 다르다.

v7을 현재 시스템 구조에 맞게 생성된 ID이며 유닉스기반 시간으로 작성하고 로그, 메트릭 등 다양한 시스템 통합에 장점이 있습니다.
v6과의 차이는 시간 기준과 타 시스템 연계가 다릅니다.
v6 시간은 그레고리안 에폭(1582-10-15) 기준이며 최신 시스템과의 시간 연동을 하려면 추가 변환이 필요합니다.
그렇다면 v7은 유닉스 에폭(1970-01-01) 기준입니다. 레거시에 따라 적용하되 신규 시스템은 v7을 권장합니다.


UUID v7에서 값 뽑는 방식

UUID v7는 시간순 정렬 가능하고 랜덤성이 보장됩니다.
랜덤 부분에서 하위 일부 비트만 사용해서 짧은 값 생성도 용이합니다.

UUID를 어떻게 사용해야할까?

대게 실무에서는 UUID를 ID로 저장하는 경우 BINARY(16)로 DB에 저장합니다.
UUID v7 자체적으로 고유성과 시간정렬이 가능하기 때문입니다.
또한, 사람이 보기 좋은 짧은 값으로도 전환하여 저장하기도 합니다.

사용방법 예시

규칙 및 조건

  • UUID ID 생성하고 저장합니다.
  • 위 기반으로 사람이 읽기 좋은 값으로 0-9, A-Z(36자리)의 조합으로 6자리로 표현한다고 해봅시다.
    • 예) yyyyMMdd-ABCDEF
  • UUID 비트 일부를 잘라서 사용
    • UUID의 동시대 기준 많이 변화되는 LSB를 잘라서 인코딩용으로 사용합니다.
    • 참고) MSB XOR LSB로 사용하면 추가적으로 랜덤성을 극대화 시킬 수 있습니다.
  • 36^6 = 약 21억 → 하루 수천만 건 이상 주문 처리에도 안전합니다.
  • 6자리 미만이 나올 경우 맨 앞자리에 “0”을 붙여 줍니다.

구현을 해보겠습니다.

  • 불변성으로 값 객체용인 record를 활용했습니다.
  • UUID v7을 사용하기 위해 외부 라이브러리를 사용했습니다.
    • java 내부 기능으로 UUID v4를 사용합니다.
    • com.github.f4b6a3:uuid-creator 라이브러리를 추가합니다.
import com.github.f4b6a3.uuid.UuidCreator;  
import java.time.*;  
import java.time.format.DateTimeFormatter;  
import java.util.UUID;    

public record OrderId(  
        UUID uuid  
) {  
    private static final DateTimeFormatter FORMATTER = DateTimeFormatter.BASIC_ISO_DATE;  
    private static final char[] BASE36 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();  

    public String createNo() {  
        // UUID의 적용된 시간을 가져옵니다.
        long epochMillis = (uuid.getMostSignificantBits() >>> 16) & 0x0000_FFFF_FFFF_FFFFL;  
        String ymd = Instant.ofEpochMilli(epochMillis)
                    .atZone(ZoneId.systemDefault())
                    .toLocalDate()
                    .format(FORMATTER);
        // 랜덤성을 향상 시키기 위해 MSB xor LSB 이후 하위 32bit를 가져옵니다.
        long randomBits = (uuid.getLeastSignificantBits() ^ uuid.getMostSignificantBits()) 
                        & ((1L << 32) - 1);  
        // 최대 자리 수를 맞추기 위해 remainder를 이용하여 값 도출합니다.(랜덤성 데이터라 무관)
        long value = randomBits % (long) Math.pow(36, 6);  
        // 나름? 인코딩된 값을 가져옵니다.
        String enc = toBase(value);
        // 5자리 이하는 맨 앞자리에 "0"을 붙여줍니다.  
        if (enc.length() < 6) enc = "0".repeat(6 - enc.length()) + enc;  
        // yyyyMMdd-ABCDEF 형태로 반환합니다.
        return ymd + "-" + enc;  
    }  

    private String toBase(long value) {  
        if( value == 0 ) return "0";  
        StringBuilder sb = new StringBuilder();  
        long v = value;  
        int length = BASE36.length;  
        while( v > 0) {  
            sb.append(BASE36[(int) (v % length)]);  
            v /= length;  
        }  
        return sb.reverse().toString();  

    }


    public static OrderId of(UUID value) {  
        Assert.notNull(value, "uuid must not be null");  
        return new OrderId(value);  
    }  

    public static OrderId create() {  
        return of(UuidCreator.getTimeOrderedEpoch());  
    }  
}
  1. UUID의 적용된 시간을 가져옵니다.
  2. 랜덤성을 향상 시키기 위해 MSB xor LSB 이후 하위 32bit를 가져옵니다.
  3. 최대 자리 수를 맞추기 위해 remainder를 이용하여 값 도출합니다.(랜덤성 데이터라 무관)
  4. toBase를 통해 나름? 인코딩된 값을 가져옵니다.
  5. 5자리 이하는 맨 앞자리에 "0"을 붙여줍니다.
  6. yyyyMMdd-ABCDEF 형태로 반환합니다.
728x90
반응형
저작자표시 비영리 (새창열림)

'보안' 카테고리의 다른 글

[암호화] 웹 보안은 SSL!  (0) 2025.08.19
[암호화] 대칭키란?  (0) 2025.08.19
단방향 암호화(해시 알고리즘)  (1) 2025.07.12
암호화(Encryption)에 대해서  (1) 2025.07.12
JCE 암호화 트러블 슈팅  (1) 2025.04.29
'보안' 카테고리의 다른 글
  • [암호화] 웹 보안은 SSL!
  • [암호화] 대칭키란?
  • 단방향 암호화(해시 알고리즘)
  • 암호화(Encryption)에 대해서
크크크크
크크크크
공뷰를 합시다.
    반응형
  • 크크크크
    Tom's Note
    크크크크
  • 전체
    오늘
    어제
    • 분류 전체보기 (129)
      • IT 지식 (5)
      • CS (66)
        • 알고리즘 & 자료구조 (19)
        • 운영체제 (41)
        • 네트워크 (1)
        • 데이터베이스 (5)
      • 보안 (6)
      • SW 공학 & 프로그래밍 언어 (5)
        • Java (28)
        • 디자인 패턴 (1)
        • 형상관리 (2)
        • 톰캣(WAS) (2)
        • SW 방법론 (3)
        • 스프링부트 (5)
      • 시스템 설계 (4)
        • Docker (2)
      • 자격증 (2)
  • 블로그 메뉴

    • 링크

    • 공지사항

    • 인기 글

    • 태그

      1급
      자바
      암호설정
      which
      chmod
      docker
      DTO
      man
      알고리즘
      분석기법
      스프링부트
      apropos
      REST API
      불변
      문제해결
      whereis
      usermod
      DI
      java
      단반향
      /etc/passwd
      whatis
      su
      passwd
      비트연산
      리눅스
      Chage
      cifs
      ADsP
      2차
    • 최근 댓글

    • 최근 글

    • 250x250
    • hELLO· Designed By정상우.v4.10.3
    크크크크
    UUID(Universally Unique Identifier) 버전과 사용법
    상단으로

    티스토리툴바