ID를 만드는 방법들

@023· May 01, 2025 · 8 min read

이번 글에서는 아이디를 생성할 때 사용되는 방법들에 대해서 정리해보려고 한다.

Sequence, Auto Increment

아이디를 생성할 때 가장 많이 사용되고 가장 쉬운 방법 중 하나는 데이터베이스 제공하는 기능을 사용하는 것일 것이다. Oracle의 Sequence, MySQL의 Auto Increment, PostgreSQL의 Serial 등이 이에 해당한다. 이렇게 하면 데이터베이스가 알아서 자동으로 아이디 값을 순서대로 생성을 해주게 된다. 그래서 아주 쉽게 아이디를 만들 수 있다는 이점이 있다 하지만 여기서 트래픽이 굉장히 많은 서비스 상황일 때에는 데이터베이스에서 아이디를 증가 시키는 작업 자체도 데이터베이스에게 적지않은 부하를 주게 된다. 또한 반드시 순서대로 생기는 것도 아니다. Oracle의 RAC의 경우 만약 4개의 노드로 구성되어 있다면 그 경우에는 4개가 각각 별도의 아이디 구간을 나눠 갖게된다. 그래서 아이디의 생성 순번하고 실제 생성 순번하고 무조건적으로는 일치하지 않게 된다. 보통 이런 Sequence나 Auto Increment 같은 경우는 보통 8byte 혹은 4byte의 길이의 숫자로 되어있다.

UUIDv4

위에서 말한 Sequence나 Auto Increment 말고 흔히 쉽게 생각할 수 있는 것이 UUID(Universally Unique Identifier)이다. 자바의 경우 UUID V4버전을 사용한다. 이 버전의 경우에는 임의의 값을 생성해서 UUID를 만들어낸다. 이에 UUID는 워낙 개수가 많기 때문에 중복될 확률이 거의 없다고 할 수 있다. 이런 UUID를 문자열로 변환하면 예를 들어 다음과 같은 형태가 된다.

e1b0c2a-4f3d-4e8b-9f1c-5d6e7f8a9b0c

이렇게 36자리의 문자열로 변환이 되는데 이 중에 -이 4개고, 16진수로 표현된 문자가 32개가 된다. 이것을 bit 단위로 표현하면 128bit가 된다. 이를 바이너리로 변환하면 16byte가 되어서 공간을 아낄 수 있다. 이러한 UUID는 서버에서 생성을 하기 때문에 데이터베이스에 부하를 주지 않게 된다. 그리고 아이디 생성을 하게 되는 서버가 많은 분산 환경에서도 적합하다고 할 수 있다. 데이터베이스 인덱스에서 클러스터형 인덱스는 PK를 기준으로 데이터를 정렬해 저장하지만, UUID는 정렬된 순서가 아닌 랜덤하게 생성되기 때문에 인덱스가 비효율적으로 저장될 수 있다. 이렇게 되면 INSERT 과정에서 인덱스/데이터의 이동이 더 많이 발생하게 되고, 최신 데이터가 조회되는 상황에서 데이터 캐시 효율도 떨어지게 된다.

UUIDv7

앞서 언급한 대로 클러스터형 인덱스를 사용할 때 발생하는 UUIDv4의 단점을 보완하기 위해서 UUIDv7이 등장했다. 버전 7은 앞자리 48bit는 타임스탬프, 뒤에 80bit는 랜덤값으로 구성되어 있다. 그래서 UUIDv7을 생성하게 되면 UUIDv4와는 다르게 생성된 시간 순서대로 정렬이 가능하다. 그래서 클러스터형 인덱스에 적합한 형태로 저장이 가능하지만 여전히 36글자인 건 변함이 없다.

Snowflake

데이터가 쌓이면 쌓일수록 아이디가 차지하는 데이터 공간 또한 커진다. 그래서 생성된 시간 순서대로 아이디를 만둘어 내는 방법을 연구해서 나온 것 중 하나가 Snowflake이다. Snowflake는 Twitter에서 만든 아이디 생성기이다. Snowflake는 8byte, 64bit의 정수형으로 아이디를 생성한다. 맨 앞에 부호bit 1bit, 밀리초로 시간을 표현하는 타임스탬프 41bit, 프로세스 수준에서 서롤를 구분할때 사용하기 위한 머신 아이디 10bit, 그 다음에는 시퀀스 12bit로 구성되어 있다.

머신 아이디 10bit는 210=10242^{10} = 1024개로 1024개의 프로세스에서 동시에 아이디를 생성할 수 있다. 같은 서비스를 하는 프로세스가 1024개까지 되기에 엄청 큰 서비스에도 가능하다는 것이다. 시퀀스 bit 또한 12bit로 212=40962^{12} = 4096개로 1ms에 4096개의 아이디를 생성할 수 있는데, 이것은 매 밀리초마다 0으초 초기화되는 카운터로 생각하면 된다. 즉, 1ms에 4096개의 중복되지 않는 아이디를 생성할 수 있다는 것이다. 초당 한 프로세스에서 40만개의 아이디를 만들어 낼만큼의 트래픽을 커버 할 수 있다는 것이다.

이러한 Snowflake에서 머신 아이디나 시퀀스 등을 조정한 변형들이 Mastodon, Sonyflake, TSID 등이 있다.

그럼 어떤 것을 써야 할까?

글로벌 서비스가 아니고, 트래픽도 많지 않고, 프로세스가 몇개 안되는 서비스라면 Auto Increment나 Sequence를 사용해도 괜찮다. 또는 YYYMMDDHHMMSS-랜덤 형식 형태로 아이디를 만들어도 충분하다.

하지만 최신 데이터를 많이 읽고, 데이터 쓰기가 많다면 UUID 보다는 정렬 순서되는 ID(클러스터형 인덱스)를 고려해서 UUIDv7를 사용하는 것이 좋다.

오랜 시간이 지나도 데이터가 쌓일 것 같고, 트래픽이 많고, 프로세스가 많다면 Snowflake를 사용하는 것이 좋다.

만약 RDB가 아니라면 사용할 저장소의 특성을 고려해 해시값 같은 ID 생성 규칙을 고려하는 것이 좋을 것 같다.

@023
focus and hustle