31 марта 2022 года на сайте IETF был официально размещен текст рабочего документа (копия 1, копия 2) New UUID Formats (далее – стандарт), который должен формально обновить, а фактически заменить давно устаревший и изначально ущербный RFC 4122.
В стандарте представлены новые форматы универсальных уникальных идентификаторов (UUID), имеющих следующие свойства:
для использования в высоконагруженных приложениях и базах данных – как монолитных, так и распределенных,
возрастающие по времени генерации (без дополнительных секунд),
содержащие таймстемп, счетчик с инициализацией его сегментов нулем и псевдослучайным значением, а также собственно псевдослучайное значение,
объединенные с метаданными.
Стандарт рекомендует поставщикам СУБД обеспечить создание и хранение UUID новых форматов для использования в качестве идентификаторов или левых частей идентификаторов, таких как, помимо прочего:
первичные ключи,
суррогатные ключи для хронологических баз данных,
внешние ключи, включая используемые в полиморфных отношениях,
ключи для пар ключ-значение в столбцах JSON и базах данных типа «ключ-значение».
В долгих и жарких спорах удалось выработать стандарт по существу безупречного качества. Хотя некоторые туманные формулировки и прежние неудачные варианты технических решений сохранились в тексте, однако найдены оригинальные и красивые решения всех проблем. Стоит особенно отметить творческий вклад жителя Японии с псевдонимом LiosK и разумные решения инициаторов стандарта Brad Peabody и Kyzer Davis из США. Стандартом обеспечена максимально возможная скорость поиска записей по содержащемуся в них значению UUID. Стандарт содержит множество правильных рекомендаций с обоснованием. Единственный существенный изъян стандарта – это расточительное использование 6 из 128 битов UUID (сегменты ver и var) лишь для совместимости с отжившим RFC 4122. Стандарт превосходит ULID, KSUID, CUID и остальные аналоги. Все они были исследованы и указаны в стандарте.
Стандарт еще не утвержден, но поставщики СУБД уже могут начинать его реализовывать. Невозможно представить, что появится другой – более качественный и существенно отличающийся вариант стандарта. Приложенные к стандарту прототипы на языке C сильно упрощенные, и поэтому они не могут быть хорошей основой для разработки. Из трех предложенных форматов наибольшую практическую ценность представляет версия UUIDv7.
В текущую версию стандарта из-за нехватки времени не вошли альтернативные текстовые кодировки UUID. Инициаторы стандарта хотят включить их в следующую версию стандарта, причем кодировка Crockford’s Base32 уже ими одобрена.
Хотя стандарт предоставляет разработчикам генераторов UUID значительную свободу в очерченных рамках, но эталонная структура UUID, которая обсуждалась при выработке стандарта, следующая:
Обозначение в стандарте | Позиция сегмента в UUID слева направо | Длина, битов | Двоичное значение или алгоритм расчета | Предназначение |
unix_ts_ms | 1 | 48 | Количество миллисекунд с полуночи (00:00:00) 1 января 1970 года по всемирному координированному времени (UTC) минус дополнительные секунды | Обеспечение монотонности записываемых UUID. Таймстемп с миллисекундной точностью, отстающий от UTC на десятки секунд. Миллисекунда - это максимально возможная точность для упорядочения по моменту времени генерации UUID, приходящих из разных источников |
ver | 2 | 4 | "0111" | Версия UUIDv7. Смысл этого сегмента лишь в совместимости с RFC 4122 |
rand_a | 3 | 1 | Сегмент счетчика, инициализируемый нулем каждую миллисекунду | Защита от переполнения счетчика при маловероятной неудачной инициализации счетчика большим псевдослучайным значением |
4 | 11 | Сегмент счетчика, инициализируемый псевдослучайным значением каждую миллисекунду | Счетчик обеспечивает монотонность UUID из одного источника, генерируемых в течение миллисекунды. Инициализация счетчика псевдослучайным значением уменьшает вероятность коллизий UUID | |
var | 5 | 2 | "10" | Вариант, детально описанный в стандарте или в RFC 4122, в отличие от других упомянутых в RFC 4122 вариантов. Смысл этого сегмента лишь в совместимости с RFC 4122 |
rand_b | 6 | 12 | Сегмент счетчика, инициализируемый псевдослучайным значением каждую миллисекунду | Счетчик должен быть достаточно длинным для защиты от переполнения, но не слишком длинным, чтобы ускорить желательный двоичный поиск UUID по старшим битам. В течение миллисекунды весь счетчик увеличивается на единицу для каждого следующего UUID |
7 | 50 | Псевдослучайное значение, сгенерированное отдельно для каждого UUID | В отличие от сегмента счетчика, инициализируемого псевдослучайным значением каждую миллисекунду, этот сегмент затрудняет угадывание близких по значению UUID с одинаковыми таймстемпами | |
обозначение отсутствует | справа от UUID в идентификаторе, используемом в качестве уникального или суррогатного ключа | любая | Кастомный сегмент, который может быть составным | См. под таблицей возможные элементы кастомного сегмента |
Возможные элементы кастомного сегмента:
дополнительное псевдослучайное значение
тип сущности или код таблицы базы данных
пространство имен
shard (сегмент) или partition (секция)
код источника данных
код типа операции или типа сообщения
контрольная сумма
другие элементы, специфичные для приложения