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 (секция)
-
код источника данных
-
код типа операции или типа сообщения
-
контрольная сумма
-
другие элементы, специфичные для приложения
Автор:
SergeyProkhorenko