TECH 으로 돌아가기
TECH HACKER NEWS 7분 읽기 34 READS

UUIDv7의 타임스탬프를 믿으면 안 되는 이유

분산 시스템과 데이터베이스 설계에서 UUIDv7은 최근 몇 년 사이 사실상 표준에 가까운 선택지로 떠올랐다. UUIDv4의 완전한 무작위성 대신 ID 앞부분에 밀리초 단위 타임스탬프를 심어, 생성 순서에 가깝게 정렬되고 데이터베이스 인덱스 효율이 좋아진다는 점이 매력으로 꼽혀 왔다. 많은 기술 블로그가 UUIDv7의 장점으로 시간 순 정렬, 생성 시각 추출 가능, 인덱스 지역성 등을 내세운다. 그러나 이런 속성들은 RFC 9562가 '반드시' 보장하는 것이 아니며, 오히려 규격을 준수하면서도 이 속성들을 극단적으로 위반하는 구현이 존재한다. 규격이 엄격하게 보장하는 것은 사실상 고유성과 그에 따른 충돌 회피뿐이다.

타임스탬프가 생성 시각이 아닐 수 있다

가장 흔한 오해는 ID에 박힌 타임스탬프를 객체의 생성 시각으로 그대로 써도 된다는 생각이다. 그러면 별도의 created_at 컬럼이나 인덱스를 두지 않아도 되니 운영이 간결해진다. 하지만 PostgreSQL의 uuid_extract_timestamp 문서조차 '추출된 타임스탬프가 UUID가 생성된 시각과 정확히 같다는 보장은 없다'고 명시적으로 경고한다. 이는 규격 자체가 그런 여지를 열어 두었기 때문이다. RFC 9562 §6.1은 구현이 실제 타임스탬프를 변경할 수 있으며(MAY alter), 그 값이 실제 시각과 얼마나 가까워야 하는지에 대해 어떤 요구나 보장도 하지 않는다고 적고 있다. §6.2는 더 나아가 구현이 타임스탬프를 실제 시각보다 앞당길(increment ahead) 수 있다고 허용한다. 즉 ID 안의 시각은 상황에 따라 현재 시각과 임의로 큰 차이를 보일 수 있다.

이 문제는 이론에 그치지 않는다. 대표적으로 파이썬 표준 라이브러리의 UUIDv7 구현이 특정 조건, 예컨대 카운터가 넘칠 때 타임스탬프를 앞당긴다. 문제는 시스템 시계가 과거로 되돌아가는 순간이다. 이 구현은 임베디드 타임스탬프가 뒤로 가는 것을 허용하지 않기 때문에, 시계가 되돌아가면 생성기가 증가 사이클에 갇혀 타임스탬프가 실제 시각보다 끝없이 앞으로 질주할 수 있다. 원문 분석에 따르면 초당 1건을 넘는 부하에서는 시스템 시계와의 차이가 수렴하지 않고 무한히 벌어졌다. 파이썬 개발자들은 이 동작이 RFC에 부합하고 다른 구현과도 일관되며 '결함 있는 시스템' 위에서는 할 수 있는 일이 많지 않다고 판단했는데, 실제로 여러 구현에서 같은 양상이 관찰된다는 점에서 이 판단 자체는 타당하다.

노드 간 단조 증가는 원래 불가능하다

UUIDv7 RFC가 여러 노드에 걸쳐 단조 증가하는 ID 생성 방법을 기술한다는 점은 의외다. 이런 종류의 전역 순서화는 1970년대에 이미 불가능함이 증명되었고, 그 결과로 벡터 클록 같은 기술이 등장했다. 근본 원인은 간단하다. 시스템 시계는 충분한 정밀도로 동기화할 수 없고, 타임스탬프 기반 정렬은 정확한 현재 시각을 알아야만 성립한다. 시각에 불확실성이 있으면 이벤트 순서에도 그만큼 불확실성이 생긴다. 그래서 유사한 ID 포맷들은 대개 '거의 정렬됨(nearly sorted)'이라는 완화된 표현을 쓰는데, UUIDv7은 오히려 더 강한 주장을 하면서 그것을 지키지 못한다. 밀리초, 특히 서브밀리초 단위 타임스탬프는 노드 간에서 신뢰하기 어렵다.

단일 노드, 단일 구현에서도 엄격한 단조 증가는 보장되지 않는다. 카운터 없이 밀리초 타임스탬프만 쓰는 구현이라면 작은 for 루프 안에서도 손쉽게 순서가 뒤집힌 ID가 나온다. 규격 어디에도 ID가 반드시 증가한다는 보장은 없으며, 서브밀리초 타임스탬프나 카운터, 잘 동기화된 시계를 갖춘 특정 구현이 상대적으로 더 나을 뿐이다. 시계가 과거로 되돌아가는 경우에 대비해 마지막으로 사용한 타임스탬프를 기록해 역행을 막는 방법이 있지만, 재부팅이나 프로세스 재시작 후에도 유효하려면 그 값을 영속 저장소에 써야 한다. 저자가 살펴본 여러 구현 중 타임스탬프를 영속 저장하는 것은 없었고, 따라서 시계가 되돌아간 직후 프로세스가 재시작되면 순서가 뒤틀린 ID가 생성된다.

실무자가 던져야 할 질문

ID에 시각이 박혀 있다는 사실은 보안 측면에서도 함의를 갖는다. ID를 공유하면 그 시각 정보도 함께 공유되기 때문이다. 예컨대 계정 생성 시점을 노출하지 않도록 설계한 프로필 페이지라도, URL에 담긴 UUIDv7이 고정밀 생성 시각을 흘릴 수 있다. 저자는 보안 평가에서 이보다 훨씬 심각한 문제를 더 자주 만난다며 이 항목의 우선순위를 낮게 두지만, 메타데이터 노출이 중요한 맥락에서는 분명히 주의가 필요하다고 짚는다.

결국 UUIDv7은 여러 아이디어를 섞어 놓고 구현자가 원하는 대로 취사선택하게 둔 포맷에 가깝다. 구현마다 제공하는 속성과 그 확실성의 폭이 넓고, 같은 구현이라도 RFC를 준수하는 선에서 동작을 바꿀 수 있다. 분산 시스템의 여러 하위 시스템이 서로 다른 구현을 섞어 쓰면 속성도 제각각이 된다. 직접 구현한다면 필요한 속성을 갖추도록 만들 수 있지만, 대부분은 표준 라이브러리나 외부 구현에 의존하므로 남의 결정에 좌우된다. 그러니 확실히 기대할 수 있는 것은 강력한 충돌 회피와 고유성뿐이라고 보는 편이 안전하다. 그렇다고 지금 UUIDv7을 걷어낼 필요는 없다. 대략적인 정렬만으로도 충분히 유용한 경우가 많기 때문이다. 다만 채택한 구현이 시계 역행을 어떻게 다루는지, 타임스탬프를 앞당기거나 영속화하는지, 카운터 크기는 어떤지를 먼저 확인하고, 타임스탬프를 생성 시각으로 신뢰할 수 있다거나 ID가 엄격히 순서대로 증가한다는 가정은 내려놓아야 한다.

SOURCE · HACKER NEWS
원문 전체 보기 → https://alexsci.com/blog/uuidv7-is-weird/
SHARE
NEXT · CHOOSE

변화를 읽었다면,
내가 만들 수익 구조를 고릅니다.

정보를 더 모으는 데서 멈추지 않고, 광고·외주·판매·중개·구독 중 내 상황에 맞는 출발점을 정해보세요.

21가지 수익 구조 살펴보기 →
처리 중...