UUID란 무엇인가?
UUID(Universally Unique IDentifier)란 네트워크 상에서 중복되지 않는 ID를 만들기 위한 표준 규약이다. 로컬에서 ID를 관리한다면 어떤 아이디들이 생성되었는지 확인한 후 중복을 체크하는 것이 가능하지만, 네트워크 상에서는 이야기가 다르다. 네트워크는 ID를 관리하는 중앙 관리자가 없기 때문에 중복 확인이 불가능하다. 따라서 네트워크 상에서 중복되지 않는 ID를 만들려면 중복되는 확률이 0에 가까운, 매우 낮은 확률을 가지는 ID를 만드는 방법을 사용해야 한다.
"중복되는 확률이 0에 가까운, 매우 낮은 확률을 가지는 ID를 만드는" 방법을 표준화 한 것이 바로 UUID이다. UUID는 계속해서 생성해도 중복이 생길 가능성이 0에 가깝다.
UUID의 구성
UUID는 8-4-4-4-12 형태의 문자이다. 각 문자는 16진수 숫자이며, 예를 들면 아래와 같은 형태이다.
eaaa2618-b2aa-4bb8-9721-0ef0a2400f77
각 부분에 대한 설명은 다음과 같다. HexDigits가 바로 8-4-4-4-12 형태인 것을 볼 수 있다.
Field | Bytes | Hex Digits | Bits | 설명 |
time_low | 4 | 8 | 32 | 시간의 하위 32비트 |
time_mid | 2 | 4 | 16 | 시간 중간 16비트 |
time_hi_and_version | 2 | 4 | 16 | 가장 높은 4비트는 버전, 다음 12비트는 시간의 높은 16비트 |
clock_seq_hi_and_res clock_seq_low |
2 | 4 | 16 | UUID 버전4 기준 난수 |
node | 6 | 12 | 48 | 노드 ID의 48비트 |
시간을 기반으로 구성된 부분들 : time_low, time_mid, time_hi_and_version
"time_low", "time_mid", "time_hi_and_version" 필드는 UUID의 시간을 기반으로 구성된 부분을 나타낸다. "clock_seq_hi_and_res clock_seq_low" 필드는 Clock Sequence와 UUID variant 를 뜻한다. 마지막으로, "node" 필드는 UUID의 고유한 노드 식별자를 나타낸다.
UUID의 시간 기반 구성 요소는 UUID가 생성된 시간을 나타내며, 60비트의 값을 가지고, 각 단위 사이의 간격은 100나노초이다. 이 중 아래의 32비트가 바로 time_low이며, 이를 시간의 하위 32비트(Time Low 32 Bits)라 표현한다. 이후 중간 값이 16비트가 되고, 이후의 time_hi_and_version이 나머지 12비트를 포함하면서 총 60비트가 된다. time_hi_and_version은 버전 비트인 4비트를 포함해서 총 16비트를 가지게 된다.
clock_seq_hi_and_res, clock_seq_low 구성 방법
"clock_seq_hi_and_res" 와 "clock_seq_low"는 버전 마다 다른 값을 가지는데, Kotlin, Java에서 사용하는 UUID.random() 는 버전 4의 UUID가 사용되며 이는 난수를 기반으로 생성된다.
이 값은 UUID 버전마다 다른데 이를 자세히 들어가면 끝도 없기 때문에 간단하게 차이를 알아보자.
- 버전1 : 시간 기반 UUID, "clock_seq_hi_and_res" 필드의 가장 높은 2비트는 항상 "10"로 설정
- 버전2 : 버전 1과 동일하지만 "clock_seq_hi_and_res" 필드의 가장 높은 2비트는 "11"로 설정
- 버전3, 5 : 네임스페이스 기반 해시값
- 버전4 : 랜덤 값(난수), "clock_seq_hi_and_res" 필드의 가장 높은 2비트는 "10"로 설정되고 "clock_seq_low" 필드는 16비트의 랜덤 값으로 구성됨
node
node도 UUID 버전별로 다르게 식별자를 생성한다.
- 버전1 : 48비트는 MAC주소 16비트는 랜덤 값으로 생성
- 버전4 : 랜덤으로 생성
- 버전3, 5 : 네임스페이스, 이름 기반으로 생성
UUID의 충돌 확률
즉, UUID는 중복되기 어려운 값들을 수없이 길게 만듦으로써 단일 값을 보장한다. UUID가 충돌할 확률은 2의 122승 분의 1이며 이에 대한 충돌은 거의 불가능에 가깝다.
자 이제 각 언어별로 UUID 만들어보도록 하자.
언어별 UUID만드는 법
Kotlin UUID 만들기
Kotlin은 Java와 호환되기 때문에 java.util 패키지의 UUID 클래스를 사용해 UUID를 만들면 된다. UUID.randomUUID()를 사용하면 UUID가 UUID 클래스의 객체로 생성되며 내부 값을 출력하려면 toString()을 사용하면 된다.
import java.util.UUID
val uuid = UUID.randomUUID().toString()
println(uuid)
Java UUID 만들기
Kotlin에서 Java의 UUID 클래스를 가져다 쓰기 때문에, Java는 Kotlin과 만드는 방법이 같다.
import java.util.UUID;
String uuid = UUID.randomUUID().toString();
System.out.println(uuid);
JavaScript UUID 만들기
다른 언어들과 달리 JavaScript는 UUID를 생성하기 위해 uuid 패키지가 필요하다. uuid 패키지는 터미널에서 다음 명령어로 설치할 수 있다.
npm install uuid
uuid패키지의 uuidv4를 사용하면 UUID를 만들 수 있다. uuidv4() 함수를 사용하면 UUID가 랜덤으로 생성된다.
const { v4: uuidv4 } = require('uuid');
const uuid = uuidv4();
console.log(uuid);
C# UUID 만들기
C#은 Guid를 사용해 UUID를 만든다. Guid.NewGuid()를 호출하면 랜덤한 UUID가 생성된다. 이 값에서 문자열을 추출하려면 ToString()을 써야 한다.
using System;
var uuid = Guid.NewGuid().ToString();
Console.WriteLine(uuid);
Python UUID 만들기
Python은 uuid 패키지의 uuid.uuid4() 메서드를 사용하면 랜덤한 UUID가 생성된다.
import uuid
uuid_value = uuid.uuid4()
print(uuid_value)