UUID v4, UUID v7, ULID, Nano ID를 한 번에 여러 개 만듭니다. 데이터베이스 시드, 테스트 작성, 픽스처 채우기에 씁니다.
UUID v4는 122비트의 난수일 뿐이라 고유하지만 정렬 순서가 뒤죽박죽입니다. 그래서 v4 키를 데이터베이스 인덱스에 넣으면 쓰기가 B-트리 전체로 흩어지고 테이블이 커질수록 느려집니다. UUID v7은 앞쪽 비트에 밀리초 타임스탬프를 넣어 이 문제를 해결합니다. 새 값이 항상 뒤에 정렬되어 인덱스에 유리하면서도 추측할 수는 없습니다.
ULID는 같은 문제를 26자 Crockford base32 형태로 풀어 더 짧고 대소문자를 가리지 않으며, NanoID는 UUID 형식을 버리고 URL에 넣기 좋은 짧은 문자열을 냅니다. 모두 브라우저의 암호학적 난수원에서 생성하므로 추측되면 안 되는 식별자로 써도 됩니다.
중앙에서 관리하지 않아도 무작위 식별자를 믿을 수 있는 근거는 낙관이 아니라 산수입니다. UUID v4는 122비트의 무작위 값을 담고, 생일 문제 계산에 따르면 충돌 확률이 50%가 되는 지점은 10의 18제곱 규모입니다. 어떤 시스템이 평생 만들어 낼 양보다 훨씬 큽니다. 실무에서 훨씬 중요한 것은 그 무작위성이 어디서 왔느냐입니다. Math.random() 으로 조립한 UUID에는 122비트에 해당하는 실제 엔트로피가 없고, 그렇게 만든 식별자가 운영 환경에서 충돌한 사례가 있습니다. 이 페이지에서 만들어지는 값은 모두 브라우저의 암호학적 난수원을 씁니다. 보장과 기대의 차이가 거기서 갈립니다.
앞쪽 비트에 타임스탬프를 넣는 것이 v7과 ULID를 데이터베이스 인덱스에 친화적으로 만드는 이유이고, 동시에 그 값이 레코드가 언제 만들어졌는지를 그대로 말해 주는 이유이기도 합니다. 대개는 무해하지만 가끔은 아닙니다. 공개된 URL에 식별자가 노출되면 가입 순서와 생성 시각이 함께 드러나고, 두 개를 나란히 놓으면 그 사이의 간격까지 드러납니다. ULID에는 같은 밀리초 안에서 만들어진 여러 값도 만들어진 순서대로 정렬되도록 하는 단조 증가 모드가 있습니다. 식별자가 정렬을 따라가는 것이 아니라 정렬 자체를 담당할 때 중요한 부분입니다.
길이는 의식적으로 골라야 할 또 하나의 축입니다. UUID는 하이픈까지 세면 36자, ULID는 26자이고 대소문자를 구분하지 않으며, NanoID는 기본값이 21자입니다. 64자짜리 URL 안전 알파벳에서 뽑은 126비트라서 v4 UUID보다 열 글자 적으면서 엔트로피는 조금 더 많습니다. 짧다는 것은 값을 소리 내어 읽거나 손으로 입력하거나 어딘가에 인쇄할 때 의미가 있고, 대소문자를 구분하지 않는다는 것은 값이 대소문자를 바꾸는 시스템을 지나갈 수 있을 때 의미가 있습니다. 반대편의 논거는 저장 공간입니다. UUID는 16바이트짜리 전용 컬럼에 들어가지만 문자열 형태들은 변환하지 않는 한 텍스트로 저장됩니다.
UUID는 자기 버전을 스스로 밝히므로, 낯선 값도 한눈에 읽을 수 있습니다. 열세 번째 16진 자리, 즉 세 번째 묶음의 첫 글자가 버전 번호입니다. 거기가 4면 무작위이고 7이면 시간 순서를 가진 것입니다. 네 번째 묶음의 첫 글자는 변형을 나타내는데, 흔히 쓰이는 모든 버전이 따르는 표준 배치에서는 8, 9, a, b 중 하나입니다. 이 검사를 통과하지 못하는 값은 잘못 생성된 UUID라기보다 애초에 UUID였던 적이 없는 문자열입니다. 잘린 해시나 손으로 적어 넣은 자리 표시자가 식별자 행세를 하며 돌아다니는 경우입니다.
됩니다. 다만 큰 테이블이라면 v4보다 UUID v7이나 ULID를 쓰세요. 시간 순 접두사 덕분에 삽입 시 인덱스 지역성이 훨씬 좋습니다.
현실적인 규모에서는 확률이 무시할 수준입니다. 여기 모든 형식은 암호학적 난수를 사용합니다.
UUID는 추측하기 어려운 식별자로는 적당하지만 권한과는 무관합니다. 시크릿이나 API 키에는 엔트로피가 명시된 전용 생성기를 쓰세요.