RFC 9562 Universally Unique Identifiers (UUIDs)

Internet Engineering Task Force (IETF)                          K. Davis
Request for Comments: 9562                                 Cisco Systems
Obsoletes: 4122                                               B. Peabody
Category: Standards Track                                        Uncloud
ISSN: 2070-1721                                                 P. Leach
                                                University of Washington
                                                                May 2024

Universally Unique Identifiers (UUIDs)

Глобально уникальные идентификаторы (UUID)

PDF

Аннотация

В этой спецификации определены глобально уникальные идентификаторы UUID (Universally Unique Identifier), которые называют также GUID (Globally Unique Identifier), и пространство имён Uniform Resource Name для UUID. UUID имеют размер 128 битов и предназначены для обеспечения пространственной и временной уникальности. Изначально UUID применялись в сетевой вычислительной системе Apollo Network Computing System (NCS), затем в среде распределенных вычислений DCE (Distributed Computing Environment) фонда OSF (Open Software Foundation) и платформах Microsoft Windows.

Данная спецификация основана на спецификации OSF DCE с любезного разрешения OSF (сейчас известен как The Open Group). Информация из ранних версий спецификации OSF DCE также включена в документ. Данный документ отменяет RFC 4122.

Статус документа

Документ относится к категории Internet Standards Track.

Документ является результатом работы IETF1 и представляет согласованный взгляд сообщества IETF. Документ прошёл открытое обсуждение и был одобрен для публикации IESG2. Дополнительные сведения о документах Internet Standard приведены в разделе 2 RFC 7841.

Информацию о текущем статусе документа, ошибках и способах обратной связи можно найти по ссылке https://www.rfc-editor.org/info/rfc9562.

Авторские права

Авторские права (Copyright (c) 2025) принадлежат IETF Trust и лицам, указанным в качестве авторов документа. Все права защищены.

К документу применимы права и ограничения, указанные в BCP 78 и IETF Trust Legal Provisions и относящиеся к документам IETF (http://trustee.ietf.org/license-info), на момент публикации данного документа. Прочтите упомянутые документы внимательно. Фрагменты программного кода, включённые в этот документ, распространяются в соответствии с пересмотренной лицензией BSD (Revised BSD License), как указано в параграфе 4.e документа IETF Trust Legal Provisions, без каких-либо гарантий (как указано в Revised BSD License).

1. Введение

Эта спецификация определяет пространство имён Uniform Resource Name для глобально уникальных идентификаторов (UUID), называемых также GUID. UUID имеет размер 128 битов и не требует централизованной регистрации.

Применение UUID очень широко распространено в вычислительных системах. UUID образуют ядро инфраструктуры идентификаторов для многих операционных систем, таких как Microsoft Windows, и приложений, таких как Web-браузер Mozilla. Во многих случаях идентификаторы могут раскрываться (expose) разными нестандартными способами.

Эта спецификация пытается стандартизовать практику применения как максимально открытую так, чтобы она приносила пользу всем в рамках Internet. Представленные здесь сведения предназначены служить кратким руководством для желающих реализовать услуги с использованием UUID в сочетании с URN [RFC8141] или иначе.

Имеются документы ITU-T Recommendation и ISO/IEC Standard [X667], основанные на [RFC4122]. Оба набора спецификаций согласованы и полностью совместимы технически. Ничто в этом документе не следует считать отменой стандартов DCE, определяющих UUID.

2. Мотивация

Одной из основных причин широкого применения UUID является отсутствие централизованного администрирования (хотя два формата могут использовать необязательные IEEE 802 Node ID, в остальных этого нет). В результате генерацию по запросу можно полностью автоматизировать и применять идентификаторы с разными целями. Описанный здесь алгоритм генерации UUID поддерживает очень высокую скорость (10 миллионов и более идентификаторов в секунду на одной машине), что позволяет при необходимости использовать UUID даже в качестве идентификаторов транзакций.

UUID имеют фиксированный размер (128 битов), который достаточно мал по сравнению с другими вариантами. Это хорошо подходит для сортировки, упорядочивания и хэширования всех видов, хранения в базах данных, простого выделения и программирования в целом.

Поскольку UUID уникальны и постоянны, они очень хороши в качестве URN. Возможность генерации UUID без регистрации делает UUID одними из наиболее дешёвых URN.

2.1. Причины обновления

С момента создания UUID многое было изменено. Современным приложениям требуется создание и использование UUID в качестве первичных идентификаторов для различных элементов в сложных вычислительных системах, включая ключи баз данных, имена файлов машин или систем, идентификаторы транзакций по событиям и многое другое.

Одной из областей, где UUID популярны, являются ключи баз данных (БД). Это связано со всё более распределенной природой современных приложений. В таких случаях системы автоинкремента, часто применяемые в БД, уже не работают хорошо, а согласование порядковых номеров через сеть может стать проблемой. Возможность применения UUID в распределённых системах в качестве уникальных и сравнительно коротких значений, не требующих координации, является хорошим вариантом, но UUID версий 1-5, определённые в [RFC4122], не обладают некоторыми желаемыми характеристиками, как указано ниже.

  1. Версии UUID без упорядочения по времени (такие как UUIDv4, см. параграф 5.4) имеют слабую локальность индексов БД. Это означает, что новые значения, созданные последовательно, не размещаются в индексе близко одно к другому, что требует их вставки в случайные места. В результате снижение производительности основных используемых структур (B-tree и варианты) может быть значительным.

  2. 100-наносекундная Григорианская эпоха во временных метках UUIDv1 (параграф 5.1) необычна и её трудно точно представить с использованием стандартных форматов чисел, таких как описаны в [IEEE754].

  3. Для упорядочения по времени требуется самопроверка/синтаксический анализ вместо обычного побайтового сравнения.

  4. Возникают проблемы приватности и сетевой безопасности при использовании адреса MAC3 в поле узла (node) UUIDv1. Раскрываемые MAC-адрес может применяться в атаках для определения местоположения сетевых интерфейсов и раскрытия иных сведений о соответствующих машинах (как минимум, производитель, а, возможно и другие детали). Кроме того, с появлением виртуальных машин и контейнеров уникальность MAC-адресов не гарантируется.

  5. Многие детали реализации, заданные в [RFC4122], предполагали компромиссы, которые невозможно соблюсти для всех приложений и которые не являются необходимыми для совместимости реализаций.

  6. В [RFC4122] не различаются требования к генерации и простому хранению UUID, хотя они зачастую разные.

В связи с отмеченными проблемами многие распределенные приложения БД и крупные поставщики приложений пытались разработать более совершенные универсальные идентификаторы на основе времени, которые можно сортировать и применять в качестве ключей БД. Это привело к появлению за последние 10 с лишним лет множества реализаций, решающих одну и ту же проблему слегка различающимися способами.

При подготовке этой спецификации были проанализированы указанные ниже 16 разных реализаций на предмет размера идентификаторов, схемы битов, лексического форматирования и кодирования, типа временных меток, их формата и точности, формата и компонентов узлов, обработки коллизий и последовательности генерации с множеством временных меток.

  1. [ULID]

  2. [LexicalUUID]

  3. [Snowflake]

  4. [Flake]

  5. [ShardingID]

  6. [KSUID]

  7. [Elasticflake]

  8. [FlakeID]

  9. [Sonyflake]

  10. [orderedUuid]

  11. [COMBGUID]

  12. [SID]

  13. [pushID]

  14. [XID]

  15. [ObjectID]

  16. [CUID]

Рассмотрение этих реализаций с учётом отмеченных проблем привело к созданию этого документа с UUID, решающими эти проблемы. Кроме того, документ [RFC4122] нуждался в переработке для решения ряда вопросов.

  1. Исправление замеченных ошибок, связанных в основном с размещением битов, ведущим к несовместимости реализаций [Err1957], [Err3546], [Err4975], [Err4976], [Err5560] и т. п.

  2. Отвязывание других версий UUID от битовой схемы UUIDv1, чтобы поля (такие как time_hi_and_version) не требовалось указывать в UUID, не основанных на времени, а также предоставление определений для UUIDv3, UUIDv4 и UUIDv5, аналогичных UUIDv1.

  3. Представление опыта реализации в реальных сценариях и крайних случаях, отмеченных в имеющихся прототипах реализаций.

  4. Представление опыта и проблем безопасности для современной эпохи в отношении адресов MAC, алгоритмов хэширования, защищённых случайных значений и др.

  5. Предоставление стандартизованных вариантов для конкретных реализаций и/или экспериментов с UUID.

  6. Предоставление тестовых векторов для иллюстрации реальных UUID, созданных по этой спецификации.

3. Терминология

3.1. Уровни требований

Ключевые слова необходимо (MUST), недопустимо (MUST NOT), требуется (REQUIRED), нужно (SHALL), не нужно (SHALL NOT), следует (SHOULD), не следует (SHOULD NOT), рекомендуется (RECOMMENDED), не рекомендуется (NOT RECOMMENDED), возможно (MAY), необязательно (OPTIONAL) в данном документе интерпретируются в соответствии с BCP 14 [RFC2119] [RFC8174] тогда и только тогда, когда они выделены шрифтом, как показано здесь.

3.2. Сокращения

ABNF

Augmented Backus-Naur Form — расширенная форма Бакуса-Наура

CSPRNG

Cryptographically Secure Pseudorandom Number Generator — криптографически защищённый генератор случайных чисел

DBMS

Database Management System — система управления базами данных (СУБД)

IEEE

Institute of Electrical and Electronics Engineers — институт инженеров по электротехнике и электронике

ITU

International Telecommunication Union — Международный союз электросвязи (МСЭ)

MAC

Media Access Control — управление доступом к среде

MD5

Message Digest 5 — дайджест сообщения 5

MSB

Most Significant Bit — наиболее значимый (старший) бит

OID

Object Identifier — идентификатор объекта

SHA

Secure Hash Algorithm — защищённый алгоритм хэширования

SHA-1

Secure Hash Algorithm 1 — защищённый алгоритм хэширования со 160-битовым дайджестом сообщения

SHA-3

Secure Hash Algorithm 3 — защищённый алгоритм хэширования (произвольный размер)

SHA-224

Secure Hash Algorithm 2 — защищённый алгоритм хэширования со 224-битовым дайджестом сообщения

SHA-256

Secure Hash Algorithm 2 — защищённый алгоритм хэширования со 256-битовым дайджестом сообщения

SHA-512

Secure Hash Algorithm 2 — защищённый алгоритм хэширования со 512-битовым дайджестом сообщения

SHAKE

Secure Hash Algorithm 3 based on the KECCAK algorithm — защищённый алгоритм хэширования на базе KECCAK

URN

Uniform Resource Names — унифицированные имена ресурсов

UTC

Coordinated Universal Time — универсальное координатное время

UUID

Universally Unique Identifier — глобально уникальный идентификатор

UUIDv1

Universally Unique Identifier version 1 — глобально уникальный идентификатор версии 1

UUIDv2

Universally Unique Identifier version 2 — глобально уникальный идентификатор версии 2

UUIDv3

Universally Unique Identifier version 3 — глобально уникальный идентификатор версии 3

UUIDv4

Universally Unique Identifier version 4 — глобально уникальный идентификатор версии 4

UUIDv5

Universally Unique Identifier version 5 — глобально уникальный идентификатор версии 5

UUIDv6

Universally Unique Identifier version 6 — глобально уникальный идентификатор версии 6

UUIDv7

Universally Unique Identifier version 7 — глобально уникальный идентификатор версии 7

UUIDv8

Universally Unique Identifier version 8 — глобально уникальный идентификатор версии 8

4. Формат UUID

Размер UUID составляет 16 октетов (128 битов), а структура определяется битами полей variant и version, как описано ниже. Биты UUID нумеруются от 0 до 127, а октеты — от 0 до 15.

При отсутствии иных явных спецификаций приложения или протокола представления каждое поле кодируется, начиная со старшего байта (сетевой порядок байтов — network byte order).

Сохранение UUID в двоичной форме выполняется упорядочением всех полей в формате big-endian. Однако известно, что GUID компонентной модели объектов (Component Object Model или COM) компании Microsoft используют порядок little-endian. Рассмотрение этого вопроса выходит за рамки спецификации (см. [MS_COM_GUID]).

UUID можно представлять в двоичном или целочисленном формате. При использовании с URN или в тексте приложений UUID следует представлять строками hex-and-dash, состоящими из нескольких групп шестнадцатеричных цифр (в верхнем или нижнем регистре), разделённых одиночными тире/дефисами. Использование в БД описано в параграфе 6.13.

Формальное определение строкового представления UUID имеет показанную ниже форму ABNF [RFC5234].

   UUID     = 4hexOctet «-»
              2hexOctet «-»
              2hexOctet «-»
              2hexOctet «-»
              6hexOctet
   hexOctet = HEXDIG HEXDIG
   DIGIT    = %x30-39
   HEXDIG   = DIGIT / «A» / «B» / «C» / «D» / «E» / «F»
f81d4fae-7dec-11d0-a765-00a0c91e6bf6

Рисунок 1. Пример строкового формата UUID.


Отметим, что буквы могут быть как строчными, так и прописными (включая те и другие в одном значении), как указано в параграфе 2.3 [RFC5234]. Пример текстового представления UUID показан на рисунке 1.

Значение UUID на рисунке 1 может быть представлено в двоичной форме (рисунок 2), целым числом (рисунок 3) или как URN (рисунок 4) [RFC8141].

111110000001110101001111101011100111110111101100000100011101000\
01010011101100101000000001010000011001001000111100110101111110110

Рисунок 2. Пример двоичного формата UUID.

329800735698586629295641978511506172918

Рисунок 3. Пример целочисленного UUID без знака (десятичное значение).

urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6

Рисунок 4. Пример URN для UUID.


Имеется много других форматов представления UUID и ниже приведены примеры некоторых из них.

  • Некоторые реализации UUID (например, [Python] и [Microsoft]) выводят UUID в форме строк в фигурных скобках, включая символы тире.

  • В [X667] дано определение формата UUID для использования UUID с OID.

  • [IBM_NCS] содержит устаревшую спецификацию уникального формата UUID, совместимого с Variant 0xx из таблицы 1.

4.1. Поле Variant

Поле variant определяет схему UUID. Интерпретация всех остальных битов зависит от установки битов этого поля. Поэтому было бы точнее назвать его полем типа, но здесь сохранено исходное название для совместимости. Поле variant включает переменное число старших битов октета 8 в UUID. Содержимое поля variant показано в таблице 1, x указывает, что бит не имеет значения.

Таблица 1. Варианты UUID.

MSB0

MSB1

MSB2

MSB3

Вариант

Описание

0

x

x

x

14-7

Резерв. Совместимость с системой сетевых вычислений (Network Computing System или NCS). Включает Nil UUID (см. параграф 5.9).

1

0

x

x

8-9,A-B

Вариант, описываемый в этом документе.

1

1

0

x

C-D

резерв. Совместимость со старыми версиями Microsoft Corporation.

1

1

1

x

E-F

Резерв для будущих определений, включая Max UUID (параграф 5.10).

Совместимость с вариантами, не указанными здесь не гарантируется, но это вряд ли будет проблемой на практике.

Биты 64 и 65 в UUID (биты 0 и 1 октета 8) должны быть установлены в соответствии со строкой 2 таблицы 1, поэтому во всех схемах битов и полей эти биты не указаны.

4.2. Поле Version

Номер версии указывается четырьмя старшими битами октета 6 (биты 48 — 51 в UUID). В таблице 2 показаны все версии для UUID variant 10xx, задаваемые этим документом.

Таблица 2. Версии UUID Variant 10xx, заданные этой спецификацией.

MSB0

MSB1

MSB2

MSB3

Версия

Описание

0

0

0

0

0

Не используется.

0

0

0

1

1

UUID на основе григорианского времени, заданные этим документом.

0

0

1

0

2

Резерв для версии DCE Security со встроенными POSIX UUID.

0

0

1

1

3

Заданная этим документом версия на основе имени с хэшированием MD5.

0

1

0

0

4

Случайно или псевдослучайно генерируемая версия, заданная этим документом.

0

1

0

1

5

Заданная этим документом версия на основе имени с хэшированием SHA-1.

0

1

1

0

6

Заданный здесь UUID на базе григорианского времени со сменой порядка.

0

1

1

1

7

Заданный этим документом UUID на основе времени Unix Epoch.

1

0

0

0

8

Резерв для пользовательских форматов, заданных этим документом.

1

0

0

1

9

Резерв для будущих определений.

1

0

1

0

10

Резерв для будущих определений.

1

0

1

1

11

Резерв для будущих определений.

1

1

0

0

12

Резерв для будущих определений.

1

1

0

1

13

Резерв для будущих определений.

1

1

1

0

14

Резерв для будущих определений.

1

1

1

1

15

Резерв для будущих определений.

Примеры версии и варианта в соответствии с таблицей приведены на рисунке 5, где M представляет размещение версии для шестнадцатеричного значения 0x4 (0b0100), а N — размещение варианта для одного из 4 возможных значений варианта 10xx: 0x8 (0b1000), 0x9 (0b1001), 0xA (0b1010), 0xB (0b1011).

00000000-0000-4000-8000-000000000000
00000000-0000-4000-9000-000000000000
00000000-0000-4000-A000-000000000000
00000000-0000-4000-B000-000000000000
xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx

Рисунок 5. Примеры UUIDv4 Variant.


Следует отметить, что остальные варианты из таблицы 1 используют разные механизмы субтипов или версионирования. Запись и определение остальных комбинаций вариантов и субтипов UUID выходит за рамки документа.

5. Схемы UUID

Для минимизации путаницы в части назначения битов и разных версий определения записей UUID предоставляются как группы полей в строка по 4 октета, начиная со старшего.

5.1. UUID версии 1

UUIDv1 базируется на времени и содержит 60-битовую метку времени в формате UTC в виде числа интервалов по 100 наносекунд с момента времени 00:00:00.00 15 октября 1582 (дата григорианской реформы христианского календаря).

UUIDv1 включает также поле clock_seq для предотвращения дубликатов, которые могут возникать при переводе часов назад или смене идентификатора узла (Node ID).

Поле node содержит адрес IEEE 802 MAC, который обычно является адресом хоста или случайным значением, созданным в соответствии с параграфами 6.9 и 6.10.

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                           time_low                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|           time_mid            |  ver  |       time_high       |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|var|         clock_seq         |             node              |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                              node                             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Рисунок 6. Схема полей и битов UUIDv1.


time_low

32 младших бита 60-битовой стартовой метки времени (биты 0 — 31, октеты 0 — 3).

time_mid

Средние 16 битов 60-битовой стартовой метки времени (биты 32 — 47, октеты 4 — 5).

ver

4-битовое поле версии, заданное в параграфе 4.2, со значением 0b0001 (1) (биты 48 — 51, октет 6).

time_high

12 старших5 битов 60-битовой стартовой метки времени (биты 52 — 63, октеты 6 — 7).

var

2-битовое поле варианта, заданное в параграфе 4.1, со значением 0b10 (биты 64 — 65, октет 8).

clock_seq

14-битовое поле упорядочения часов (биты 66 — 79, октеты 8 — 9).

node

48-битовый пространственно-уникальный идентификатор (биты 80 — 127, октеты 10 — 15).

Для систем, не имеющих доступа к UTC, но поддерживающих местное время, это время можно применять взамен UTC при условии согласованности времени во всей системе. Однако это не рекомендуется, поскольку получить UTC из местного времени можно просто вычитанием значения часового пояса.

Если часы переведены назад или это могли отстать (например, за время нахождения системы в выключенном состоянии) и генератор UUID не может быть уверен в отсутствии UUID, созданных с большим значением временной метки, значение поля clock_seq должно быть изменено. Если прежнее значения поля известно, его можно инкрементировать, в противном случае в поле следует поместить высококачественное псевдослучайное значение.

При смене Node ID (например, при переносе сетевого адаптера в другую машину) установка в поле clock_seq случайного значения минимизирует вероятность дубликата из-за незначительной разницы времени в машинах. Если значение clock_seq, связанное с измененным Node ID, известно, его можно инкрементировать (маловероятно).

Поле clock_seq должно исходно (один раз за время существования системы) инициализироваться случайным значением для минимизации сходства (корреляции между системами). Это обеспечивает максимальную защиту в случае быстрого переноса Node ID от системы к системе. Исходному значению недопустимо коррелировать с Node ID.

Замечания для идентификаторов узлов на основе IEEE 802

  • В системах с несколькими адресами IEEE 802 можно использовать любой доступный адрес.

  • В системах без адреса IEEE должно использоваться случайное или псевдослучайное значение (см. параграфы 6.9 и 6.10).

  • В системах с 64-битовым адресом MAC можно использовать 48 младших (правых) битов.

  • Системам с 16-битовым адресом IEEE 802.15.4 следует применять взамен его 64-битовый MAC-адрес (можно использовать младшие 48 битов). Как вариант, можно сгенерировать 32 случайных бита и добавить их в конец 16-битового MAC-адреса для создания 48-битового значения.

5.2. UUID версии 2

UUIDv2 предназначены для DCE Security UUID (см .[C309] [C311]), поэтому определение здесь не приводится.

5.3. UUID версии 3

UUIDv3 предназначены для создания UUID по именам, которые берутся из некого пространства имён и уникальны в нём (см. параграф 6.5). Значения UUIDv3 создаются путём расчёта хэш-значения MD5 [RFC1321] для данного значения Namespace ID (параграф 6.6), объединённого (конкатенация) со значением желаемого имени, после их приведения к канонической последовательности октетов, заданной стандартами или соглашениями пространства имён, в сетевом порядке байтов. Значение MD5 помещается в UUID, затем устанавливаются поля version и variant в соответствии с параграфами 4.2 и 4.1 (см. пример в Приложении A.2). Информация о выборе канонического формата желаемого имени приведена в параграфе 6.5 (Замечание об именах).

По возможности вместо UUIDv3 следует применять UUIDv5. Сведения о безопасности MD5 приведены в [RFC6151].

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                            md5_high                           |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|          md5_high             |  ver  |       md5_mid         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|var|                        md5_low                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                            md5_low                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Рисунок 7. Схема полей и битов UUIDv2.


md5_high

48 старших (слева) битов рассчитанного значения MD5 (биты 0 — 47, октеты 0 — 5).

ver

4-битовое поле версии, заданное в параграфе 4.2, со значением 0b0011 (3) (биты 48 — 51, октет 6).

md5_mid

12 младших (справа) из 16 битов рассчитанного значения MD5, следующих за md5_high (биты 52 — 63, октеты 6 — 7).

var

2-битовое поле варианта, заданное в параграфе 4.1, со значением 0b10 (биты 64 — 65, октет 8).

md5_low

62 младших (справа) битов из оставшихся 64 битов рассчитанного значения MD5 (биты 66 — 127, октеты 8 — 15).

5.4. UUID версии 4

UUIDv4 предназначена для генерации UUID из действительно случайных или псевдослучайных значений.

Реализация может генерировать 128 битов случайных данных и заполнять ими структуру UUID (рисунок 8). Затем поля version и variant устанавливаются в соответствии с параграфами 4.1 и 4.2. Как вариант, реализация может генерировать случайные значения random_a, random_b и random_c (всего 122 бита), а затем заполнить поля version и variant. Рекомендации по генерации случайных значений приведены в параграфе 6.9.

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                           random_a                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|          random_a             |  ver  |       random_b        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|var|                       random_c                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                           random_c                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Рисунок 8. Схема полей и битов UUIDv4.


random_a

Первые 48 битов, заполненные случайными данными (параграф 6.9) (биты 0 — 47, октеты 0 — 5).

ver

4-битовое поле версии, заданное в параграфе 4.2, со значением 0b0100 (4) (биты 48 — 51, октет 6).

random_b

12 дополнительных битов, заполненные случайными данными (параграф 6.9) (биты 52 — 63, октеты 6 — 7).

var

2-битовое поле варианта, заданное в параграфе 4.1, со значением 0b10 (биты 64 — 65, октет 8).

random_c

62 бита после поля var, заполненные случайными данными (параграф 6.9) (биты 66 — 127, октеты 8 — 15).

5.5. UUID версии 5

UUIDv5 предназначены для генерации UUID по «именам», которые берутся из некого пространства имён и уникальны в нем, как описано в параграфе 6.5.

Значения UUIDv5 создаются путём расчёта хэш-значения SHA-1 [FIPS180-4] для данного значения Namespace ID (параграф 6.6), объединённого (конкатенация) с желаемым именем, после их приведения к канонической форме в соответствии со стандартами или соглашениями пространства имён с сетевым порядком байтов. Старшие (слева) 128 битов значения SHA-1 помещаются в схему UUID, а оставшиеся 32 (младшие) бита SHA-1 отбрасываются. Затем в UUID заполняются поля version и variant в соответствии с параграфами 4.2 и 4.1. Пример подстановки битов и отбрасывания лишнего представлен в Приложении A.4. Информация о выборе канонического формата желаемого имени приведена в параграфе 6.5 (Замечание об именах).

Возможны ситуации (обычно в зависимости от политики безопасности), когда библиотеки SHA-1 недоступны или сочтены небезопасными для применения. Поэтому может оказаться желательной генерация UUID по именам с использованием SHA-256 или более новых методов SHA. Для таких UUID недопустимо использовать UUIDv5 и взамен должны применяться UUIDv8, заданные в параграфе 5.8. Иллюстративный пример UUIDv8 для основанных на имени идентификаторов с использованием SHA-256 приведён в Приложении B.2.

Вопросы безопасности SHA-1 рассмотрены в [RFC6194].

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                           sha1_high                           |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|         sha1_high             |  ver  |      sha1_mid         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|var|                       sha1_low                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                           sha1_low                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Рисунок 9. Схема полей и битов UUIDv5.


sha1_high

Старшие (слева) 48 битов рассчитанного значения SHA-1 (биты 0 — 47, октеты 0 — 5).

ver

4-битовое поле версии, заданное в параграфе 4.2, со значением 0b0101 (5) (биты 48 — 51, октет 6).

sha1_mid

Младшие 12 из следующих после sha1_high 16 битов рассчитанного значения SHA-1 (биты 52 — 63, октеты 6 — 7).

var

2-битовое поле варианта, заданное в параграфе 4.1, со значением 0b10 (биты 64 — 65, октет 8).

sha1_low

62 младших бита оставшейся части (старшие 128 битов) хэш-значения SHA-1 (биты 66 — 127, октеты 8 — 15).

5.6. UUID версии 6

UUIDv6 — совместимая по полям версия UUIDv1 (параграф 5.1) с переупорядочением для улучшения локальности БД. Ожидается применение UUIDv6 прежде всего в контексте использования UUIDv1. Системам, не использующим устаревшую версию UUIDv1, следует применять UUIDv7 (параграф 5.7).

Вместо расщепления временной метки на три части (low, mid, high) как в UUIDv1 версия UUIDv6 обращает последовательность битов метки времени и записывает их от старшего к младшему. Т. е. из 60-битовой метки времени, принятой в UUIDv1 (параграф 5.1) в UUIDv6 сначала берутся 48 старших битов, за которыми следует 4 бита версии и оставшиеся 12 битов исходной 60-битовой временной метки. Поле clock_seq применяется, как указано в параграфе 5.1.

Для битов clock_seq и node следует устанавливать псевдослучайные значение при каждой генерации нового UUIDv6, однако реализация может применять поведение clock_seq и MAC-адреса, описанное в параграфе 5.1. Дополнительные сведения о применении MAC-адресов в UUID представлены в разделе 8.

Формат UUIDv6 показан на рисунке 10.

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                           time_high                           |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|           time_mid            |  ver  |       time_low        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|var|         clock_seq         |             node              |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                              node                             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Рисунок 10. Схема полей и битов UUIDv6.


time_high

32 старших (слева) бита 60-битовой стартовой метки времени (биты 0 — 31, октеты 0 — 3).

time_mid

Средние 16 битов 60-битовой стартовой метки времени (биты 32 — 47, октеты 4 — 5).

ver

4-битовое поле версии, заданное в параграфе 4.2, со значением 0b0110 (биты 48 — 51, октет 6).

time_low

Оставшиеся 12 битов 60-битовой стартовой метки времени (биты 52 — 63, октеты 6 — 7).

var

2-битовое поле варианта, заданное в параграфе 4.1, со значением 0b10 (биты 64 — 65, октет 8).

clock_seq

14-битовое поле упорядочения часов (биты 66 — 79, октеты 8 — 9).

node

48-битовый пространственно-уникальный идентификатор (биты 80 — 127, октеты 10 — 15).

В UUIDv6 расщепление метки времени на time_high и time_mid необязательно, поскольку порядок 48 битов time_high и time_mid не меняется. Этот шаг остаётся полезным при использовании имеющийся реализации UUIDv1.

5.7. UUID версии 7

UUIDv7 включает упорядоченные по времени значения меток из широко применяемого и хорошо известного источника Unix Epoch — число миллисекунд, прошедших с полуночи 1 января 1970 г. UTC, без учёта високосных секунд. В общем случае UUIDv7 обеспечивает лучшую энтропию по сравнению с UUIDv1 (параграф 5.1) и UUIDv6 (параграф 5.6).

Значения UUIDv7 создаются путём размещения временной метки Unix в миллисекундах) в старших 48 битах, заполнения полей version и variant, а также размещения случайных битов в оставшихся частях UUIDv7 для обеспечения уникальности, как указано в параграфе 6.9. Как вариант, реализации могут заполнять эти 74 указанной ниже комбинацией полей для обеспечения монотонного роста в рамках 1 миллисекунды:

  1. необязательная субмиллисекундная часть метки времени (до 12 битов), см. параграф 6.2 (метод 3);

  2. необязательный счётчик с хорошей затравкой, как указано в параграфе 6.2 (метод 1 или 2);

  3. случайные данные для каждого нового значения UUIDv7 в остальных битах.

Реализациям следует, по возможности, применять UUIDv7 вместо UUIDv1 и UUIDv6.

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                           unix_ts_ms                          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|          unix_ts_ms           |  ver  |       rand_a          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|var|                        rand_b                             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                            rand_b                             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Рисунок 11. Схема полей и битов UUIDv7.


unix_ts_ms

48-битовое беззнаковое значение (big-endian) временной метки Unix Epoch в миллисекундах, как указано в параграфе 6.1 (биты 0 — 47, октеты 0 — 5).

ver

4-битовое поле версии, заданное в параграфе 4.2, со значением 0b0111 (7) (биты 48 — 51, октет 6).

rand_a

12 псевдослучайных битов для обеспечения уникальности (параграф 6.9) и/или дополнительной монотонности, как указано в параграфе 6.2 (биты 52 — 63, октеты 6 — 7).

var

2-битовое поле варианта, заданное в параграфе 4.1, со значением 0b10 (биты 64 — 65, октет 8).

rand_b

62 псевдослучайных бита для обеспечения уникальности (параграф 6.9) и/или дополнительной монотонности, как указано в параграфе 6.2 (биты 66 — 127, октеты 8 — 15). .

5.8. UUID версии 8

UUIDv8 обеспечивает формат для экспериментов и фирменных решений. Единственным требованием к этой версии является то, что биты variant и version должны быть установлены в соответствии с параграфами 4.1 и 4.2. Уникальность UUIDv8 будет зависеть от реализации и предполагать её недопустимо.

Явно определены лишь биты полей version и variant, а оставшиеся 122 контролируются реализацией. Важно отметить, что UUIDv8 не является заменой UUIDv4 (параграф 5.4), где эти 122 бита заполняются случайными значениями.

Ниже указаны примеры ситуаций, где могут применяться UUIDv8.

  • Реализация хочет включить в UUID информацию, не заданную в этом документе.

  • У реализации имеются ограничения на уровне языка или приложения, препятствующие применению стандартных UUID.

В Приложении B приведены два иллюстративных примера фирменных алгоритмов UUIDv8.

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                           custom_a                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|          custom_a             |  ver  |       custom_b        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|var|                       custom_c                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                           custom_c                            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Рисунок 12. Схема полей и битов UUIDv8.


custom_a

48 битов, заполняемых в соответствии с потребностями реализации (биты 0 — 47, октеты 0 — 5).

ver

4-битовое поле версии, заданное в параграфе 4.2, со значением 0b1000 (8) (биты 48 — 51, октет 6).

custom_b

12 битов, заполняемых в соответствии с потребностями реализации (биты 52 — 63, октеты 6 — 7).

var

2-битовое поле варианта, заданное в параграфе 4.1, со значением 0b10 (биты 64 — 65, октет 8).

custom_c

62 бита после поля var, заполняемых в соответствии с потребностями реализации 62 (биты 66 — 127, октеты 8 — 15).

5.9. Nil UUID

00000000-0000-0000-0000-000000000000

Рисунок 13. Формат Nil UUID.


Nil UUID — это особый случай UUID, где все 128 имеют значение 0.

Nil UUID может применяться для указания отсутствия иного значения UUID, если требуется или применяется 128-битовый идентификатор UUID. Nil UUID можно считать эквивалентом отсутствия нужного значения, т. е это резервное значение для особых случаев в конкретной реализации.

Отметим, что Nil UUID относится к диапазону варианта Apollo NCS в соответствии с первой строкой таблицы 1.

5.10. Max UUID

Max UUID — это особый случай UUID, где все 128 битов имеют значение 1. Этот идентификатор можно считать инверсией Nil UUID (см. параграф 5.9).

FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF

Рисунок 14. Формат Max UUID.


Max UUID можно применять в качестве контрольного значения, когда требуется 128-битовый идентификатор UUID, но такие концепции как «конец списка UUID» нужно выражать и резервировать для зависящих от реализации случаев.

Отметим, что значение Max UUID относится к диапазону ещё не определённых (yet-to-be defined) в соответствии с последней строкой таблицы 1.

6. Опыт применения UUID

Минимальные требования к генерации UUID каждой версии описаны в этом документе. Остальное отдаётся на откуп реализации. Ниже рассматриваются важные факторы, которые могут помочь разработчикам найти компромисс между разными реализациями UUID.

6.1. Временные метки

Источники, размер и точность временных меток UUID были предметом долгих дискуссий при разработке спецификации UUIDv7. Выбор правильной метки времени очень важен для приложений и в этом параграфе рассматриваются наиболее важные аспекты этого выбора.

Надёжность

Реализация получает текущую временную метку из надёжного источника для генерации упорядоченных по времени и постоянно увеличивающихся значений. Следует позаботиться о том, чтобы изменения временных меток из среды или операционной системы обрабатывались должным образом в соответствии с требованиями реализации. Например, если системные часы могут быть переведены назад из-за настройки вручную или корректировки по протоколу точного времени, реализации нужно понимать, как обрабатывать такие случаи (см. «Изменение, размытие, размазывание» ниже).

Источник

В UUIDv1 и UUIDv6 применяются временные метки Gregorian Epoch, а в UUIDv7 — Unix Epoch. Если нужны метки другой эпохи, должна применяться версия UUIDv8.

Субсекундное разрешение и точность

Для временных меток применяется множество уровней точности: миллисекунды, микросекунды, наносекунды и т. д. Кроме того, для упорядочения по времени при разных субсекундных уровнях могут применяться дробные значения. Системные часы имеют тот или иной уровень дискретности, который зачатую ниже точности, обеспечиваемой операционной системой. В настоящее время для UUIDv1 и UUIDv6 применяется дискретность в 100 нсек, а для UUIDv7 — 1 мсек для Unix Epoch, что не выше точности многих современных систем. Для других уровней точности можно применять UUIDv8. По аналогии с параграфом 6.2 для UUIDv1 и UUIDv6 можно имитировать более высокую точность временных меток, подсчитывая число UUID с одинаковым значением системного времени и создавая на основе этого дробную часть временной метки. Число меток высокого разрешения будет варьироваться от 0 до числа интервалов по 100 нсек в одном интервале системных часов.

Размер

От размера временной ветки напрямую зависит продолжительность её возможного использования в UUID до достижения максимального значения и это следует принимать во внимание при выборе типа метки. В версиях UUIDv1 и UUIDv6 применяются 60-битовые метки времени, пригодные до 52366 н. э., в UUIDv7 — 48-битовые, которые будут действовать до 10889 н. э.

Изменение, размытие, размазывание

Реализации могут изменять фактические метки времени. Примерами этого являются соображения безопасности, связанные с предоставлением реального времени в UUID для 1) корректировки неточных часов, 2) обработки високосных секунд, 3) получение значений миллисекунд путём деления на 1024 (или иное значение) по причинам производительности (вместо деления числа микросекунд на 1000). Эта спецификация не задаёт требований или гарантий точности часов (совпадения с фактическим временем). Если не требуется частая генерация UUID, метки UUIDv1 и UUIDv6 могут просто быть системным временем, умноженным на число 100-наносекундных интервалов в одном интервале системного таймера.

Заполнение

Если требуется дополнение меток времени, реализация должна заполнять старшие (слева) биты. Примером является заполнение старших битов метки Unix нулями до размера 48 битов в UUIDv7 или заполнение старших битов числом переходов 32-битовых меток Unix через 0 после 19 января 2038 г.

Отсечка

Если требуется отсечка временной метки, отбрасываться должны младшие (справа) биты. Примером может служить отсечка 16 младших битов 64-битовых меток Unix до 48 битов в UUIDv7.

Обработка ошибок

Если система перегружает генератор, запрашивая слишком много UUID в одном интервале системного таймера, служба UUID может возвращать ошибку или приостанавливать генератор UUID до смены значения системных часов. Недопустимо сознательно возвращать дубликаты значений при переходе счётчика через 0 (rollover). Отметим, что при частой перегрузке генераторов UUID системе могут быть выделены добавочные Node ID, что позволит ускорить выделение, делая потенциально доступными множество UUID для каждого значения метки. Похожие методы рассматриваются в параграфе 6.4.

6.2. Монотонность и счётчики

Монотонность (каждое следующее значение больше предыдущего) является основой для сортируемых по времени UUID на базе времени. Обычно UUID по времени из этого документа будут монотонными из-за встроенной метки времени, однако реализации могут усилить монотонность с помощью описанных ниже концепций.

Следует озаботиться монотонностью UUID при пакетной генерации. Т. е. при создании 1000 UUID для одной метки времени следует обеспечить логику упорядочения генерации этой 1000 UUID. Реализации пакетной генерации UUID могут применять монотонный счётчик, инкрементируемый для каждого UUID создаваемого с той же меткой времени.

В реализациях UUID для одного узла, которым не требуется пакетное создание UUID, встроенные метки времени UUIDv6 и UUIDv7 могут обеспечить достаточные гарантии монотонности просто за счёт создания нового UUID после того, как временная метка обновилась. Узлы распределенных систем рассматриваются в параграфе 6.4.

Реализациям для одного узла при пакетном создании UUID следует применять указанные ниже методы или обеспечивать иным способом монотонность при высокой скорости генерации UUID.

Выделенный счётчик фиксированного размера (метод 1)

Некоторые реализации выделяют определённое число битов в схеме UUID исключительно для подсчёта числа UUID созданных в течение данного интервала меток UUID. При наличии счётчика фиксированного размера он должен помещаться сразу после встроенной временной метки. Это улучшает сортировку и позволяет генерировать случайные данные для каждого увеличения счётчика. В этом случае поле rand_a (или часть его битов слева) в UUIDv7 служит выделенным счётчиком фиксированного размера, который инкрементируется при каждой генерации UUID. Случайные биты в конце rand_b (трейлер) при каждой генерации UUID помогут создавать непредсказуемые UUID. Если для счётчика нужно больше битов можно использовать также старшие (слева) биты поля rand_b.

Монотонные случайные числа (метод 2)

Этот метод позволяет использовать случайные данные как счётчик. Эти монотонные значения можно рассматривать как «счётчик со случайной затравкой», которая должна инкрементироваться в младших битах при каждой генерации UUID с данной временной меткой. В UUIDv7 для этого следует использовать поле rand_b при пакетной генерации в течение одного интервала временной метки. Приращение для каждой генерации UUID является случайным положительным целым числом желаемого размера. Это обеспечивает требуемый уровень непредсказуемости UUID за счёт базовой энтропии. Можно инкрементировать значение на 1, если важно число генерируемых в определённом интервале UUID, а предсказуемость не является проблемой. Однако не следует увеличивать счётчик на 1 в реализациях, поддерживающих непредсказуемость, поскольку значения легко угадать.

Замена старших битов для повышения точности часов (метод 3)

Для UUIDv7 с миллисекундной дискретностью меток времени можно использовать дополнительную точность часов, доступную в системе, для замены 12 случайных битов, следующих сразу за меткой времени. Это позволяет получить упорядоченные по времени значения с субмиллисекундным разрешением, используя подходящее для среды реализации число битов. В этом случае биты повышения точности должны размещаться в начале (слева) поля rand_a для UUIDv7.

Расчёт значения начинается с дробной части временной метки (доли миллисекунды в UUIDv7). Рассчитывается число значений, которые могут быть представлены доступным числом битов (4096 для поля UUIDv7 rand_a). С помощью арифметики с плавающей запятой или масштабируемой целочисленной арифметики дробная часть значения миллисекунд умножается на 4096 с округлением вниз (уменьшение) до целого числа, чтобы получить значение от 0 до максимума для выбранного числа битов. Эти числа будут монотонно возрастать со временем. Каждое возрастающее дробное значение будет приводить к росту значения используемого битового поля.

Предположим, например, системное время 1 января 2023 г. 12:34:56,1234567. С учётом точности лучше 1 мсек получим значение 0,4567 как дробную часть миллисекунды. Для кодирования этого значения в 12 битов можно взять число возможных значений этих битов (4096 или 212), умножить его на значение дробной части и отсечь результат до целого числа, что даёт 1870. Это число можно представить в шестнадцатеричной (0x74E) или двоичной (0b011101001110) форме. Затем эти 12 битов можно использовать как старшие (слева) биты поля случайного значения UUID (rand_a в UUIDv7). Это работает для любого числа битов, помещаемых в UUID, и приложение может выбрать число битов на основе доступного разрешения часов. Для UUIDv7 число ограничено 12 битами, доступными в поле случайных значений.

Основным преимуществом кодирования повышенной точности меток является возможность использования данных, доступных из системных часов, которые с высокой вероятностью будут уникальными. Это может упростить некоторые реализации. Метод можно применять в сочетании с другими, где биты дополнительной точности будут размещаться сразу после метки времени. Тогда при использовании битов упорядочения часов (clock_seq) они будут следующими.

Ниже рассматриваются вопросы создания надёжных выделенных счётчиков с фиксированным числом битов.

Затравка выделенного счётчика с фиксированным размером

Реализации со счётчиком фиксированного размера инициализируют этот счётчик случайным значением при каждом увеличении (шаге) метки времени. При неизменном значении метки счётчик инкрементируется по специальной логике. При использовании счётчика со случайной затравкой (seed) вместе с методом 1 (см. выше) случайное значение может генерироваться при каждом увеличении счётчика без влияния на сортируемость. Недостатком такого подхода является возможность переполнения счётчика при выборе недостаточного размера или нехватке места для требуемого числа приращений. Реализации со счётчиком фиксированного размера могут применять случайную инициализацию части, а не всего значения счётчика. Например, в 24-битовом счётчике можно случайно инициализировать 23 младших бита, а старший бит инициализировать 0 с целью предотвращения переполнения счётчика.

Размер выделенного счётчика с фиксированным размером

Разрядность счётчика выбирается в соответствии с уровнем точности меток времени. Например, для миллисекундной точности обычно требуется больший размер счётчика, чем для наносекундной. В общем случае следует делать размер не менее 12 битов и не более 42. Нужно выбирать размер так, чтобы обеспечивалась достаточная энтропия случайной части UUID после размещения счётчика. Энтропия позволяет улучшить непредсказуемость UUID при пакетной генерации.

Далее рассматриваются вопросы, связанные с переходом счётчика через максимум (rollover).

Защита от обнуления (rollover)

Описанная выше «Затравка счётчика фиксированного размера» полезна и для устранения перехода счётчика через 0 при достижении максимума. Это подходит и для методов с монотонным случайным счётчиком, когда гарантируется, что размер инкрементируемой части меньше общего размера случайного приращения. Это позволяет инкрементировать младшие (справа) биты счётчика без риска перехода через максимальное значение счётчика.

Обработка достижения максимума счётчика (Rollover)

Для предотвращения проблем при сортировки приложение должно обрабатывать достижение счётчиком максимума. В общем случае приложениям, озабоченным монотонностью и сортируемостью следует «замораживать» счётчик в ожидании новой временной метки, что обеспечит сохранение монотонности. Как вариант, можно инкрементировать метку за пределы текущего времени и снова инициализировать счётчик.

Для обеспечения монотонности идентификаторов UUID со встроенным счётчиком реализация может:

  1. сравнить текущую метку времени с сохранённой;

  2. если метки совпадают, счётчик инкрементируется выбранным методом;

  3. если значение текущей метки больше предыдущего, счётчик инициализируется заново выбранным методом для новой метки и генерируются новые случайные биты (если биты были заморожены или применялись в качестве затравки монотонного счётчика).

Проверка ошибок монотонности

Реализации следует проверять, что текущий созданный идентификатор UUID больше предыдущего. Нарушение этого говорит о том, что могли произойти такие события, как перевод часов, обработка високосных секунд, переполнение счётчика. В приложения следует внедрять логику обнаружения таких ситуаций и устранения проблем или хотя бы информирования о соответствующей ошибке. В общем случае приложение может для этого повторно использовать предыдущую или инкрементировать счётчик.

6.3. Состояния генератора UUID

Состояние генератора UUID (необязательное) требуется считывать из стабильного хранилища лишь один раз в процессе загрузки, если оно считывается в энергонезависимое системное хранилище (и обновляется вместе с этим хранилищем). Это стабильное хранилище можно применять для записи различных частей генерации UUID, что будет полезно при пакетной генерации и проверке ошибок монотонности в UUIDv6 и UUIDv7. Сохраняемые значения могут включать последнюю известную метку времени, поле упорядочения часов, счётчики, случайные данные и т. п.

Если реализации не доступно стабильное хранилище, она может генерировать UUID как для первого случая при пакетной генерации. Это менее желательно, поскольку повышает частоту создания таких значений, как поле упорядочения часов, счётчики и случайные данные, что повышает вероятность дубликатов. Кроме того, частая генерация случайных значений создаёт дополнительную нагрузку на источник энтропии и/или пул энтропии, служащий основой для случайных чисел. Если очень важна устойчивость к коллизиям, реализация может возвращать ошибку приложения (см. параграф 6.7).

Для UUIDv1 и UUIDv6 при неизменном Node ID (например, сетевой адаптер для Node ID не отделим от системы) или реинициализации упорядочения часов случайным значением можно возвращать текущее значение Node ID вместо его записи в стабильное хранилище. Состояние не требуется записывать в стабильное хранилище при каждой генерации UUIDv1 или UUIDv6. Для метки времени в хранилище можно периодически устанавливать значение больше уже использованного в UUID. Пока в генерируемых UUID метка времени меньше записанной в хранилище, а clock_seq и Node ID остаются неизменными, обновлять нужно лишь общую энергонезависимую копию состояния. Если значение метки в хранилище указывает в будущее на величину меньше типичного времени перезагрузки системы, отказ (перезагрузка) не приведёт к необходимости заново инициализировать clock_seq.

Если доступ к общему состоянию при каждой генерации UUID слишком дорог, можно реализовать общесистемный генератор для выделения блока меток времени при каждом вызове, которые затем будут служить для генерации UUID.

6.4. Распределённая генерация UUID

Некоторым реализациям может потребоваться использование многоузловых кластеризованных приложений, где два и более узла независимо генерируют UUID, сохраняемые в одном месте. Хотя UUID уже имеют достаточную энтропию, гарантирующую малую вероятность конфликтов, с ростом числа генерирующих узлов вероятность коллизий растёт.

В этом параграфе описаны два устойчивых к конфликтам подхода при многоузловой генерации UUID в распределенных средах. Несмотря на описание здесь двух методов, в реализациях следует применять вариант псевдослучайных Node ID, если требуется устойчивость к конфликтам при распределенной генерации UUID. Применение любого из этих методов не требует распределенной генерации UUID.

Node ID

В этом методе в структуру UUID помещается псевдослучайное значение Node ID, которое помогает гарантировать уникальность битового пространства для данного узла. В результате созданные узлом UUID не конфликтуют с UUID, созданными другими узлами (с иным Node ID ). Реализациям со встроенным идентификатором узла следует использовать UUIDv8. В качестве Node ID не следует применять адреса IEEE 802 MAC (см. раздел 8). Местоположение и число используемых битов определяется реализацией и выходит за рамки документа. Не рассматривается здесь также создание и согласование уникальных идентификаторов для каждого узла.

Централизованный реестр

В этом методе все узлы, генерирующие UUID, обращаются к центральному реестру и подтверждают уникальность созданных значений. По мере масштабирования взаимодействие с центральным реестром может стать узким местом, негативно влияющим на генерацию UUID. Этот метод не рекомендуется и выходит за рамки документа.

Распределенные приложения, генерирующие UUID на множестве хостов, должны быть готовы полагаться на источник случайных чисел каждого хоста.

6.5. Генерация UUID на основе имён

Хотя некоторые предпочитают термин «основанные на хэше» для описания UUID, применяющих алгоритмы хэширования (MD5 или SHA-1), в документе сохраняется термин «основанные на именах» для согласованности с ранее опубликованными документами и имеющимися реализациями. Требования к UUID на основе имён приведены ниже.

  • UUID, созданные из одного имени (в одном каноническом формате) в одном пространстве имён, должны быть одинаковыми.

  • UUID, созданным из разных имён (в одном или разных канонических форматах) в одном пространстве имён, следует быть разными (с высокой вероятностью).

  • UUID, созданным из одного имени (в одном или разных канонических форматах) в разных пространствах имён, следует быть разными (с высокой вероятностью).

  • Если два UUID, созданных по именам (в одном каноническом формате), совпадают, они были созданы из одного имени в одном и том же пространстве имён (с высокой вероятностью).

Замечание об именах

Понятие имени (и пространства имён) следует трактовать широко, не ограничиваясь текстовыми именами. Каноническая последовательность октетов — это последовательность, соответствующая спецификации канонической формы представления данной формы имени. Имя может иметь множество форм, из которых лишь 1 является канонической. Разработчики новых пространств имён для UUID должны указывать спецификацию канонической формы имён в этом пространстве или определять каноническую форму, если её ещё нет. Например, на момент создания этого документа в системе доменных имён ((Domain Name System или DNS) [RFC9499] было 3 формата передачи: базовый (www.example.com), для представления (www.example.com.) и для передачи в линию (3www7example3com0). Для отличительных имён [X500] (Distinguished Name или Dn) [RFC4122] разрешает принимать текстовые и двоичные (DER). Для унифицированных указателей ресурсов (Uniform Resource Locator или URL) [RFC1738] можно указать полное доменное имя (Fully Qualified Domain Name или FQDN) с идентификатором протокола или без него (www.example.com или https://www.example.com). Для идентификаторов объектов (OID) [X660] можно выбрать нотацию с точками без точки (2.999) или с точкой (.2.999) в начале, а также один из многих форматов [X680], таких как OID Internationalized Resource Identifier (OID-IRI) (/Joint-ISO-ITU-T/Example). Хотя по умолчанию большинство пользователей могут применять базовый формат для DNS, FQDN для URL, текст для X.500 и нотацию без ведущей точки для OID, реализациям UUID на основе имён обычно следует принимать ввод в любой форме. Каждый из форматов имени в пространстве имён будет давать на выходе свой UUID. Поэтому механизмы и соглашения, применяемые для выделения имён и обеспечения их уникальности в своём пространстве выходят за рамки этой спецификации.

6.6. Распределение и использование идентификаторов пространства имён

В этом параграфе описаны идентификаторы некоторых потенциально интересных пространств имён, таких как DNS [RFC9499], URL [RFC1738], OID [X660], Dns [X500]. Описаны также выделение, регистрация в IANA и другие детали.

Таблица 3. Идентификаторы пространств имён.

 

Пространство имён

Namespace ID

Документ

для имени

для идентификатора

DNS

6ba7b810-9dad-11d1-80b4-00c04fd430c8

[RFC9499]

[RFC4122], RFC 9562

URL

6ba7b811-9dad-11d1-80b4-00c04fd430c8

[RFC1738]

[RFC4122], RFC 9562

OID

6ba7b812-9dad-11d1-80b4-00c04fd430c8

[X660]

[RFC4122], RFC 9562

X500

6ba7b814-9dad-11d1-80b4-00c04fd430c8

[X500]

[RFC4122], RFC 9562

 

Элементы добавляются в реестр по процедуре Specification Required [RFC8126]. Распределение Namespace ID назначенными экспертами показано ниже.

  • Первое значение Namespace ID для DNS было рассчитано из UUIDv1 на основе времени и в качестве стартовой точки служит 6ba7b810-9dad-11d1-80b4-00c04fd430c8.

  • В последующих значениях Namespace ID увеличивается младший (справа) бит time_low 6ba7b810, а для остальной части UUID фиксируется значение 9dad-11d1-80b4-00c04fd430c8.

  • Новые значения Namespace ID должны использовать такую же логику и недопустимо выдавать ранее использованные значения Namespace ID.

  • Таким образом, для следующего Namespace ID доступно значение time_low 6ba7b815 а полный идентификатор будет иметь значение 6ba7b815-9dad-11d1-80b4-00c04fd430c8.

  • Верхней границей time_low в случае значений Namespace ID является ffffffff (полный идентификатор ffffffff-9dad-11d1-80b4-00c04fd430c8), что должно обеспечить достаточно места для будущих значений Namespace ID.

Отметим, что 6ba7b813-9dad-11d1-80b4-00c04fd430c8 и его использование не заданы этим документом и [RFC4122], поэтому его не следует применять значение Namespace ID.

Новые Namespace ID должны документироваться в соответствии с разделом 7, если они должны быть глобально доступны и совместимы. Реализации могут продолжать специфичные для поставщика, приложения или внедрения значения Namespace ID, но это не гарантирует совместимости. Для таких ID недопустимо применять указанную выше логику и взамен рекомендуется Namespace ID UUIDv4 или UUIDv7. Если вероятность конфликтов (параграф 6.7) и уникальность (параграф 6.8) UUID на основе имени не являются проблемой, реализация может применять при создании Namespace ID для приложения версию UUIDv8. Реализациям следует возможность ввода пользовательских пространств имён для вновь зарегистрированных IANA Namespace ID сверх указанных выше, а также специфичных для приложения Namespace ID.

6.7. Устойчивость к конфликтам

Реализациям следует учитывать последствия конфликтов UUID в приложениях и при выборе между версиями UUID, использующими энтропию (случайность), и другими компонентами, такими как описаны в параграфах 6.1 и 6.2. Это особенно важно для устойчивости к конфликтам в распределенных системах, как описано в параграфе 6.4. Ниже приведены два примера, иллюстрирующие разный уровень влияния конфликтов на приложение.

Слабое влияние

Конфликт UUID вызывает появление дубликата записи в системном журнале, что искажает статистику, полученную на основе данных. Реализации, на которые не влияют конфликты, могут продолжать использование энтропии и уникальности, обеспечиваемых UUID, заданными в этом документе.

Сильное влияние

дубликат ключа ведёт к получению самолётом неверного курса, что ставит под угрозу жизнь людей. В таких случаях нет места для ошибок. Конфликтов необходимо избегать, отказы недопустимы. Приложения, работающие в таких условиях, должны обеспечивать максимальную устойчивость к конфликтам в рамках заданного контекста.

6.8. Глобальная и локальная уникальность

Созданные по этой спецификации UUID могут применяться для обеспечения гарантий локальной уникальности. Например, в случаях, когда не нужна глобальная уникальность вне приложения, уникальности созданных в рамках локального приложения UUID может быть достаточно для БД. Хотя абсолютную глобальную уникальность невозможно обеспечить без схемы обмена данными, для практической уникальности UUID такая схема не требуется. Реализации могут при необходимости использовать общую схему обмена данными, описанную в параграфе 6.4для повышения уровня уникальности, обеспечиваемого данной спецификацией.

6.9. Непредсказуемость

Реализациям следует применять криптозащищенный генератор псевдослучайных чисел (CSPRNG) для создания трудно предсказуемых значений с низкой вероятностью коллизий (уникальность). Исключением являются случаи недоступности CSPRNG в среде исполнения. Следует озаботиться подобающим обновлением состояния CSPRNG в таких ситуациях, как ветвление процессов. CSPRNG гарантирует, что лучшие решения из параграфов 6.7 и 8 будут в современных UUID. Дополнительные сведения по созданию случайных чисел криптографического качества даны в [RFC4086], [RFC8937], [RANDOM].

6.10. UUID, не идентифицирующие хост

В этом параграфе описана генерация UUIDv1 или UUIDv6 в случаях недоступности или нежелательности применения адресов IEEE 802. Реализации могут использовать методы рандомизации MAC-адресов [IEEE802.11bh] в качестве альтернативы псевдослучайной логике, описанной в этом параграфе. Как вариант, реализации могут выбрать получение 48-битового псевдослучайного числа криптографического качества в соответствии с параграфом 6.9 для использования в качестве Node ID. После генерации 48-битового случайного идентификатора узла реализация должна установить в младшем бите первого октета Node ID значение 1. Этот бит служит для указания индивидуального или группового адреса и никогда не устанавливается в адресах IEEE 802 реальных сетевых плат. Поэтому не может возникать конфликтов между UUID, созданных на машинах с сетевым адаптером и без такового. Пример генерации случайного 48-битового значения и его последующего использования приведён в Приложении A. Дополнительные сведения об адресах IEEE 802, битах unicast/multicast и local/global приведены в [RFC9542].

Отметим, что для совместимости с прежними спецификациями здесь используется бит unicast/multicast, а не более корректный local/global, поскольку в сети возможны MAC-адреса с обоими значениями бита local/global. С битом unicast/multicast этого не происходит, поскольку узел не может иметь группового адреса.

Такие элементы, как имя компьютера или операционной системы не являются строго случайными, но могут помочь в различении результатов из разных систем.

Точный алгоритм генерации Node ID зависит от конкретной системы, поскольку доступные данные и функции очень часто зависят от системы. Базовый подход заключается в сборе как можно большего числа источников в буфер, создании дайджеста сообщения (например, SHA-256 или SHA-512 [FIPS180-4]), взятия из хера 6 произвольных байтов и установки бита multicast, как указано выше.

6.11. Сортировка

UUIDv6 м UUIDv7 устроены так, что реализации, которым нужна сортировка (например, индексов БД), могут обрабатывать идентификаторы как неразобранные (raw) байты без необходимости из разбора или анализа. Упорядоченные по времени монотонные UUID выигрывают от большей локальности индексов БД, поскольку новые значения индексов размещаются близко друг к другу. В результате объекты лучше группируются для повышения производительности. Реальные различия при таком подходе и случайной вставке данных могут составлять порядок величины и больше.

Форматы UUID, соответствующие этой спецификации, предназначены для лексической сортировки в текстовом представлении. UUID создаются с сетевым порядком байтов (big-endian). Если нужен обратный порядок (little-endian), можно использовать UUIDv8.

6.12. Непрозрачность

В общем случае рекомендуется избегать ненужного анализа значений UUID, используя их как «непрозрачные» (opaquely). Хотя задачи приложений могут требовать того или иного анализа (introspection), например, полей var (параграф 4.1) и ver (параграф 4.2) или временных меток UUID, рекомендуется избегать таких операций. Соблюдение этих рекомендаций упростит приложения, повысит их совместимость и производительность.

6.13. Вопросы БД и СУБД

Для многих приложений (например, БД) сохранение UUID в форме текста избыточно, поскольку требует 288 битов для представления 128-битовых значений UUID. По возможности, UUID для БД следует сохранять в 128-битовой двоичной форме. В других системах UUID можно хранить в двоичном или текстовом виде.

  • Двоичная форма обеспечивает экономию места и может ускорять доступ.

  • Текстовая форма занимает больше места, но требует меньше трансляций, что может упростить реализации.

Производителям систем управления базами данных (СУБД) рекомендуется обеспечивать функции генерации и хранения UUID в заданных здесь форматах для применения в качестве идентификаторов (или их части), таких как первичные ключи, суррогатные ключи для временных БД, внешние ключи для полиморфных отношений, ключи пар key-value в столбцах JSON и БД и т. п. В приложениях с монолитными БД созданные базой (а не клиентом) UUID могут быть более монотонными. UUID могут дополняться другими идентификаторами для обеспечения целостности и обратной связи.

Разработчикам БД рекомендуется не использовать UUID на основе имён (параграфы 5.3 и 5.5) в качестве первичных ключей таблиц. Основной проблемой при проектировании БД является допущение о неизменности определённых значений, которое на деле оказывается ошибкой. Почтовые индексы, номера лицензий и другие идентификационные номера и т. п. кажутся уникальными и неизменными в данный момент времени, а позднее возникают обстоятельства, требующие их замены. Изменение идентификатора, служившего вводом name для UUID на основе имени, может привести к аннулированию структуры БД. Для таких случаев отмечено, что использование UUID, не основанных на имени, будет приводить к тому, что рассматриваемое поле будет размещено там, где легче адаптироваться к изменениям (исключая первичные ключи). В общем случае с учётом отмеченных проблем рекомендуется избегать естественных ключей в виде UUID на основе имён и применять суррогатные ключи UUID на основе времени.

7. Взаимодействие с IANA

Все ссылки на [RFC4122] в реестрах IANA (за исключением созданных этим документом) заменены ссылками на этот документ, включая регистрацию пространства имён IANA URN [URNNamespaces] для UUID. Ссылки на параграф 4.1.2 в [RFC4122] заменены ссылками на раздел 4 данного документа.

Агентству IANA нужно отслеживать субтипы UUID и особые случаи Namespace IDs Values, как указано в параграфах 7.1 и 7.2 в реестре <https://www.iana.org/assignments/uuid>. При оценке запросов назначенным экспертам следует учитывать отклики сообщества, чёткость определения базовой спецификации и её требования. Значения, зависимые от производителя, приложения или конкретного внедрения, не регистрируются. Технические документы следует публиковать в стабильном виде с обеспечением свободного доступа (в идеале с указанием URL), но они не обязаны быть стандартами. Назначенные эксперты одобряют или отклоняют запрос на регистрацию и сообщают об этом в IANA. В отказ следует включать объяснение причин и, если это применимо, рекомендации по изменению.

7.1. Реестр IANA UUID Subtypes и регистрация в нём

Эта спецификация задаёт реестр UUID Subtypes для широко применяемых стандартов UUID.

Таблица 4. Субтипы IANA UUID.

 

Имя

ID

Субтип

Вариант

Документ

Gregorian Time-based

1

version

OSF DCE / IETF

[RFC4122], RFC 9562

DCE Security

2

version

OSF DCE / IETF

[C309], [C311]

MD5 Name-based

3

version

OSF DCE / IETF

[RFC4122], RFC 9562

Random

4

version

OSF DCE / IETF

[RFC4122], RFC 9562

SHA-1 Name-based

5

version

OSF DCE / IETF

[RFC4122], RFC 9562

Reordered Gregorian Time-based

6

version

OSF DCE / IETF

RFC 9562

Unix Time-based

7

version

OSF DCE / IETF

RFC 9562

Custom

8

version

OSF DCE / IETF

RFC 9562

 

Значения в реестр могут добавляться по процедуре Standards Action [RFC8126]. Требования указаны ниже.

  • Минимальное и максимальное значение ID для субтипа version варианта OSF DCE / IETF должно находиться в диапазоне от 0 до 15. Версии из таблицы 27 указанные как резервные или не используемые, не включаются в реестр IANA до подобающего определения.

  • В столбце «Субтип» содержится текст произвольной формы. На момент публикации этого документа были лишь два субтипа UUID — version и family. Субтип family относится к пространству вариантов Apollo NCS (выходит за рамки этой спецификации). Вариант Microsoft может иметь механизм субтипов, однако эти субтипы не известны и выходят за рамки спецификации. Варианты «Резерв для будущих определений» могут вносить новые субтипы в будущем. Значения идентификаторов (Subtype ID) могут перекрываться, например, ID может существовать в нескольких вариантах.

  • В столбце «Субтип» содержится текст произвольной формы. Вероятно будет применяться 4 значения: OSF DCE / IETF, Apollo NCS, Microsoft и значение, относящееся к варианту «Резерв для будущих определений». В будущем могут быть добавлены новые имена.

7.2. Реестр IANA UUID Namespace ID и регистрация в нём

Эта спецификация задаёт реестр UUID Namespace IDs для широко используемых значений Namespace ID. Детали регистрации, включая рекомендации для назначенных экспертов, приведены в параграфе 6.6.

8. Вопросы безопасности

Реализациям не следует предполагать сложность угадывания UUID. Например, недопустимо использовать UUID как средства защиты (идентификаторы для получения доступа). Наличие предсказуемости в источнике случайных чисел приведёт к появлению уязвимости. Реализациям недопустимо предполагать простоту обнаружения незначительных изменений UUID для перенаправления ссылки на другой объект. Человек не может проверить целостность UUID простым взглядом.

MAC-адресам присущи риски в части конфиденциальности (приватности), поэтому не следует применять их в UUID. Взамен следует брать данные CSPRNG из источника с достаточной энтропией, обеспечивающего уникальность при создании UUID (см. параграфы 6.9 и 6.10).

Метки времени в UUID открывают очень небольшой фронт атак. Метка времени в сочетании с встроенным счётчиком говорит о порядке создания UUID и соответствующих данных, но не раскрывает ничего о самих данных или приложении в целом. Если UUID нужны для операций защиты в контексте приложения в той или иной форме, следует применять UUIDv4 (параграф 5.4).

Вопросы безопасности для MD5 рассмотрены в [RFC6151], для SHA-1 — в [RFC6194].

9. Литература

9.1. Нормативные документы

[C309] X/Open Company Limited, «X/Open DCE: Remote Procedure Call», ISBN 1-85912-041-5, Open CAE Specification C309, August 1994, <https://pubs.opengroup.org/onlinepubs/9696999099/toc.pdf>.

[C311] The Open Group, «DCE 1.1: Authentication and Security Services», Open Group CAE Specification C311, August 1997, <https://pubs.opengroup.org/onlinepubs/9696989899/toc.pdf>.

[FIPS180-4] National Institute of Standards and Technology (NIST), «Secure Hash Standard (SHS)», FIPS PUB 180-4, DOI 10.6028/NIST.FIPS.180-4, August 2015, <https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf>.

[FIPS202] National Institute of Standards and Technology (NIST), «SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions», FIPS PUB 202, DOI 10.6028/NIST.FIPS.202, August 2015, <https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf>.

[RFC2119] Bradner, S., «Key words for use in RFCs to Indicate Requirement Levels», BCP 14, RFC 2119, DOI 10.17487/RFC2119, March 1997, <https://www.rfc-editor.org/info/rfc2119>.

[RFC8141] Saint-Andre, P. And J. Klensin, «Uniform Resource Names (URNs)», RFC 8141, DOI 10.17487/RFC8141, April 2017, <https://www.rfc-editor.org/info/rfc8141>.

[RFC8174] Leiba, B., «Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words», BCP 14, RFC 8174, DOI 10.17487/RFC8174, May 2017, <https://www.rfc-editor.org/info/rfc8174>.

[X667] ITU-T, «Information technology — Open Systems Interconnection — Procedures for the operation of OSI Registration Authorities: Generation and registration of Universally Unique Identifiers (UUIDs) and their use as ASN.1 object identifier components», ISO/IEC 9834-8:2004, ITU-T Recommendation X.667, September 2004.

9.2. Дополнительная литература

[COMBGUID] «Creating sequential GUIDs in C# for MSSQL or PostgreSql», commit 2759820, December 2020, <https://github.com/richardtallent/RT.Comb>.

[CUID] «Collision-resistant ids optimized for horizontal scaling and performance.», commit 215b27b, October 2020, <https://github.com/ericelliott/cuid>.

[Elasticflake] Pearcy, P., «Sequential UUID / Flake ID generator pulled out of elasticsearch common», commit dd71c21, January 2015, <https://github.com/ppearcy/elasticflake>.

[Err1957] RFC Errata, Erratum ID 1957, RFC 4122, <https://www.rfc-editor.org/errata/eid1957>.

[Err3546] RFC Errata, Erratum ID 3546, RFC 4122, <https://www.rfc-editor.org/errata/eid3546>.

[Err4975] RFC Errata, Erratum ID 4975, RFC 4122, <https://www.rfc-editor.org/errata/eid4975>.

[Err4976] RFC Errata, Erratum ID 4976, RFC 4122, <https://www.rfc-editor.org/errata/eid4976>.

[Err5560] RFC Errata, Erratum ID 5560, RFC 4122, <https://www.rfc-editor.org/errata/eid5560>.

[Flake] Boundary, «Flake: A decentralized, k-ordered id generation service in Erlang», commit 15c933a, February 2017, <https://github.com/boundary/flake>.

[FlakeID] «Flake ID Generator», commit fcd6a2f, April 2020, <https://github.com/T-PWK/flake-idgen>.

[IBM_NCS] IBM, «uuid_gen Command (NCS)», March 2023, <https://www.ibm.com/docs/en/aix/7.1?topic=u-uuid-gen-command-ncs>.

[IEEE754] IEEE, «IEEE Standard for Floating-Point Arithmetic.», IEEE Std 754-2019, DOI 10.1109/IEEESTD.2019.8766229, July 2019, <https://standards.ieee.org/ieee/754/6210/>.

[IEEE802.11bh] IEEE, «IEEE Draft Standard for Information technology-Telecommunications and information exchange between systems Local and metropolitan area networks-Specific requirements — Part 11: Wireless LAN Medium Access Control (MAC) and Physical Layer (PHY) Specifications Amendment: Enhancements for Extremely High Throughput (EHT)», Electronic ISBN 978-1-5044-9520-2, March 2023, <https://standards.ieee.org/ieee/802.11bh/10525/>.

[KSUID] Segment, «K-Sortable Globally Unique IDs», commit bf376a7, July 2020, <https://github.com/segmentio/ksuid>.

[LexicalUUID] Twitter, «Cassie», commit f6da4e0, November 2012, <https://github.com/twitter-archive/cassie>.

[Microsoft] Microsoft, «2.3.4.3 GUID — Curly Braced String Representation», April 2023, <https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/222af2d3-5c00-4899-bc87-ed4c6515e80d>.

[MS_COM_GUID] Chen, R., «Why does COM express GUIDs in a mix of big-endian and little-endian? Why can“t it just pick a side and stick with it?», September 2022, <https://devblogs.microsoft.com/oldnewthing/20220928-00/?p=107221>.

[ObjectID] MongoDB, «ObjectId», <https://docs.mongodb.com/manual/reference/method/ObjectId/>.

[orderedUuid] Cabrera, I. B., «Laravel: The mysterious «Ordered UUID»», January 2020, <https://itnext.io/laravel-the-mysterious-ordered-uuid-29e7500b4f8>.

[pushID] Lehenbauer, M., «The 2^120 Ways to Ensure Unique Identifiers», February 2015, <https://firebase.googleblog.com/2015/02/the-2120-ways-to-ensure-unique_68.html>.

[Python] Python, «uuid — UUID objects according to RFC 4122», <https://docs.python.org/3/library/uuid.html>.

[RANDOM] Occil, P., «Random Number Generator Recommendations for Applications», June 2023, <https://peteroupc.github.io/random.html>.

[RFC1321] Rivest, R., «The MD5 Message-Digest Algorithm», RFC 1321, DOI 10.17487/RFC1321, April 1992, <https://www.rfc-editor.org/info/rfc1321>.

[RFC1738] Berners-Lee, T., Masinter, L., and M. McCahill, «Uniform Resource Locators (URL)», RFC 1738, DOI 10.17487/RFC1738, December 1994, <https://www.rfc-editor.org/info/rfc1738>.

[RFC4086] Eastlake 3rd, D., Schiller, J., and S. Crocker, «Randomness Requirements for Security», BCP 106, RFC 4086, DOI 10.17487/RFC4086, June 2005, <https://www.rfc-editor.org/info/rfc4086>.

[RFC4122] Leach, P., Mealling, M., and R. Salz, «A Universally Unique Identifier (UUID) URN Namespace», RFC 4122, DOI 10.17487/RFC4122, July 2005, <https://www.rfc-editor.org/info/rfc4122>.

[RFC5234] Crocker, D., Ed. And P. Overell, «Augmented BNF for Syntax Specifications: ABNF», STD 68, RFC 5234, DOI 10.17487/RFC5234, January 2008, <https://www.rfc-editor.org/info/rfc5234>.

[RFC6151] Turner, S. and L. Chen, «Updated Security Considerations for the MD5 Message-Digest and the HMAC-MD5 Algorithms», RFC 6151, DOI 10.17487/RFC6151, March 2011, <https://www.rfc-editor.org/info/rfc6151>.

[RFC6194] Polk, T., Chen, L., Turner, S., and P. Hoffman, «Security Considerations for the SHA-0 and SHA-1 Message-Digest Algorithms», RFC 6194, DOI 10.17487/RFC6194, March 2011, <https://www.rfc-editor.org/info/rfc6194>.

[RFC8126] Cotton, M., Leiba, B., and T. Narten, «Guidelines for Writing an IANA Considerations Section in RFCs», BCP 26, RFC 8126, DOI 10.17487/RFC8126, June 2017, <https://www.rfc-editor.org/info/rfc8126>.

[RFC8937] Cremers, C., Garratt, L., Smyshlyaev, S., Sullivan, N., and C. Wood, «Randomness Improvements for Security Protocols», RFC 8937, DOI 10.17487/RFC8937, October 2020, <https://www.rfc-editor.org/info/rfc8937>.

[RFC9499] Hoffman, P. And K. Fujiwara, «DNS Terminology», BCP 219, RFC 9499, DOI 10.17487/RFC9499, March 2024, <https://www.rfc-editor.org/info/rfc9499>.

[RFC9542] Eastlake 3rd, D., Abley, J., and Y. Li, «IANA Considerations and IETF Protocol and Documentation Usage for IEEE 802 Parameters», BCP 141, RFC 9542, DOI 10.17487/RFC9542, April 2024, <https://www.rfc-editor.org/info/rfc9542>.

[ShardingID] Instagram Engineering, «Sharding & IDs at Instagram», December 2012, <https://instagram-engineering.com/sharding-ids-at-instagram-1cf5a71e5a5c>.

[SID] «sid : generate sortable identifiers», Commit 660e947, June 2019, <https://github.com/chilts/sid>.

[Snowflake] Twitter, «Snowflake is a network service for generating unique ID numbers at high scale with some simple guarantees.», commit ec40836, May 2014, <https://github.com/twitter-archive/snowflake>.

[Sonyflake] Sony, «A distributed unique ID generator inspired by Twitter“s Snowflake», commit 848d664, August 2020, <https://github.com/sony/sonyflake>.

[ULID] «Universally Unique Lexicographically Sortable Identifier», Commit d0c7170, May 2019, <https://github.com/ulid/spec>.

[URNNamespaces] IANA, «Uniform Resource Names (URN) Namespaces», <https://www.iana.org/assignments/urn-namespaces/>.

[X500] ITU-T, «Information technology — Open Systems Interconnection — The Directory: Overview of concepts, models and services», ISO/IEC 9594-1, ITU-T Recommendation X.500, October 2019.

[X660] ITU-T, «Information technology — Procedures for the operation of object identifier registration authorities: General procedures and top arcs of the international object identifier tree», ISO/IEC 9834-1, ITU-T Recommendation X.660, July 2011.

[X680] ITU-T, «Information Technology — Abstract Syntax Notation One (ASN.1) & ASN.1 encoding rules», ISO/IEC 8824-1:2021, ITU-T Recommendation X.680, February 2021.

[XID] «Globally Unique ID Generator», commit efa678f, October 2020, <https://github.com/rs/xid>.

Приложение A. Тестовые векторы

Тестовые векторы UUIDv1 и UUIDv6 используют одну и ту же 60-битовую метку времени: 0x1EC9414C232AB00 (138648505420000000) — вторник, 22 февраля, 2022 2:22:22.000000 PM GMT-05:00. Совпадают также значения clock_seq и node, сгенерированные из случайных данных. Для рандомизированного значения node в младшем бите первого октета устанавливается значение 1, как указано в параграфе 6.10. Это меняет начальное значение 0x9E6BDECED846 на 0x9F6BDECED846.

Псевдокод для преобразования 64-битовых меток Unix в 100-наносекундные метки сохранен в документе для справки.

# Gregorian-to-Unix Offset:
# The number of 100 ns intervals between the
# UUID Epoch 1582-10-15 00:00:00
# and the Unix Epoch 1970-01-01 00:00:00
# Greg_Unix_offset = 0x01b21dd213814000 or 122192928000000000

# Unix 64-bit Nanosecond Timestamp:
# Unix NS: Tuesday, February 22, 2022 2:22:22 PM GMT-05:00
# Unix_64_bit_ns = 0x16D6320C3D4DCC00 or 1645557742000000000

# Unix Nanosecond precision to Gregorian 100-nanosecond intervals
# Greg_100_ns = (Unix_64_bit_ns/100)+Greg_Unix_offset

# Work:
# Greg_100_ns = (1645557742000000000/100)+122192928000000000
# Unix_64_bit_ns = (138648505420000000-122192928000000000)*100

# Final:
# Greg_100_ns = 0x1EC9414C232AB00 or 138648505420000000

Рисунок 15. Псевдокод тестового вектора метки времени.


A.1. Пример значения UUIDv1

-------------------------------------------
поле      биты  значение
-------------------------------------------
time_low   32   0xC232AB00
time_mid   16   0x9414
ver         4   0x1
time_high  12   0x1EC
var         2   0b10
clock_seq  14   0b11, 0x3C8
node       48   0x9F6BDECED846
-------------------------------------------
total      128
-------------------------------------------
final: C232AB00-9414-11EC-B3C8-9F6BDECED846

Рисунок 16. Пример тестового вектора UUIDv1.


A.2. Пример значения UUIDv3

Расчёт MD5 для DNS Namespace ID и Name со значением www.example.com показан на рисунке 17. Сопоставления и значения полей приведены на рисунке 18, а пподстановка битов version и variant — на рисунке 19.


Namespace (DNS):  6ba7b810-9dad-11d1-80b4-00c04fd430c8
Name:             www.example.com
------------------------------------------------------
MD5:              5df418813aed051548a72f4a814cf09e

Рисунок 17. Пример UUIDv3 MD5.


-------------------------------------------
поле     биты  значение
-------------------------------------------
md5_high  48   0x5df418813aed
ver        4   0x3
md5_mid   12   0x515
var        2   0b10
md5_low   62   0b00, 0x8a72f4a814cf09e
-------------------------------------------
total     128
-------------------------------------------
final: 5df41881-3aed-3515-88a7-2f4a814cf09e

Рисунок 18. Пример тестового вектора UUIDv3.

MD5 hex and dash:      5df41881-3aed-0515-48a7-2f4a814cf09e
Ver and Var Overwrite: xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
Final:                 5df41881-3aed-3515-88a7-2f4a814cf09e

Рисунок 19. Пример подстановки битов Ver/Var в UUIDv3.


A.3. Пример значения UUIDv4

-------------------------------------------
поле     биты  значение
-------------------------------------------
random_a  48   0x919108f752d1
ver        4   0x4
random_b  12   0x320
var        2   0b10
random_c  62   0b01, 0xbacf847db4148a8
-------------------------------------------
total     128
-------------------------------------------
final: 919108f7-52d1-4320-9bac-f847db4148a8

Рисунок 20. Пример тестового вектора UUIDv4.


Пример UUIDv4 создан путём генерации 16 случайных байтов со значением 919108F752D133205BACF847DB4148A8, которое применяется для заполнения полей (рисунок 20).

Подстановка битов version и variant показана на рисунке 21.

Random hex:            919108f752d133205bacf847db4148a8
Random hex and dash:   919108f7-52d1-3320-5bac-f847db4148a8
Ver and Var Overwrite: xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
Final:                 919108f7-52d1-4320-9bac-f847db4148a8

Рисунок 21. Пример UUIDv4 с подстановкой битов Ver/Var.


A.4. Пример значения UUIDv5

Расчёт SHA-1 для DNS Namespace ID и Name со значением www.example.com показан на рисунке 22. Сопоставления и значения полей приведены на рисунке 23, а подстановка битов version и variant, а также сохраняемая и отсекаемая часть — на рисунке 24.

Namespace (DNS):  6ba7b810-9dad-11d1-80b4-00c04fd430c8
Name:             www.example.com
----------------------------------------------------------
SHA-1:            2ed6657de927468b55e12665a8aea6a22dee3e35

Рисунок 22. Пример UUIDv5 SHA-1.

-------------------------------------------
поле      биты  значение
-------------------------------------------
sha1_high  48   0x2ed6657de927
ver         4   0x5
sha1_mid   12   0x68b
var         2   0b10
sha1_low   62   0b01, 0x5e12665a8aea6a2
-------------------------------------------
total      128
-------------------------------------------
final: 2ed6657d-e927-568b-95e1-2665a8aea6a2

Рисунок 23. Пример тестового вектора UUIDv5.

SHA-1 hex and dash:    2ed6657d-e927-468b-55e1-2665a8aea6a2-2dee3e35
Ver and Var Overwrite: xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
Final:                 2ed6657d-e927-568b-95e1-2665a8aea6a2
Discarded:                                                 -2dee3e35

Рисунок 24. Пример UUIDv5 с подстановкой Ver/Var и отбрасыванием части SHA-1.


A.5. Пример значения UUIDv6

-------------------------------------------
поле       биты  значение
-------------------------------------------
time_high   32   0x1EC9414C
time_mid    16   0x232A
ver          4   0x6
time_high   12   0xB00
var          2   0b10
clock_seq   14   0b11, 0x3C8
node        48   0x9F6BDECED846
-------------------------------------------
total       128
-------------------------------------------
final: 1EC9414C-232A- 6B00-B3C8-9F6BDECED846

Рисунок 25. Пример тестового вектора UUIDv6.


A.6. Пример значения UUIDv7

В этом примере UUIDv7 тестовый вектор использует общеизвестную метку времени Unix Epoch с миллисекундной точностью для заполнения первых 48 битов, а rand_a и rand_b заполняются случайными данными. Метка времени: вторник 22февраля 2022 г. 2:22:22.00 PM GMT-05:00 имеет вид 0x017F22E279B0 или 1645557742000.

-------------------------------------------
поле       биты  значение
-------------------------------------------
unix_ts_ms  48   0x017F22E279B0
ver          4   0x7
rand_a      12   0xCC3
var          2   0b10
rand_b      62   0b01, 0x8C4DC0C0C07398F
-------------------------------------------
total       128
-------------------------------------------
final: 017F22E2-79B0-7CC3-98C4-DC0C0C07398F

Рисунок 26. Пример тестового вектора UUIDv7.


Приложение B. Иллюстративные примеры

В последующих параграфах приведены примеры для иллюстрации применения UUIDv8 (параграф 5.8) в фирменной и/или экспериментальной логике, основанной на приложении. Эти примеры не прошли столь же тщательного тестирования, создания прототипов и получения откликов, как другие алгоритмы в этом документе. Авторы рекомендуют разработчикам создавать свои алгоритмы для UUIDv8, а не использовать приведённые ниже.

B.1. Пример значения UUIDv8 на основе времени

В этом тестовом векторе UUIDv8 применяется общеизвестная 64-битовая временная метка Unix Epoch с разрешением 10 нсек, отсечённая справа до 60, для заполнения полей custom_a и custom_b, с установкой для битов ver между этими полями значения 8. Устанавливаются также биты var, а поле custom_c заполняется случайными данными.

Временная метка — вторник 22февраля 2022 г. 2:22:22.000000 PM GMT-05:00 — представлена как 0x2489E9AD2EE2E00 или 164555774200000000 (шаг 10 нсек).

-------------------------------------------
поле     биты  значение
-------------------------------------------
custom_a  48   0x2489E9AD2EE2
ver        4   0x8
custom_b  12   0xE00
var        2   0b10
custom_c  62   0b00, 0xEC932D5F69181C0
-------------------------------------------
total     128
-------------------------------------------
final: 2489E9AD-2EE2-8E00-8EC9-32D5F69181C0

Рисунок 27. Пример UUIDv8 на основе времени.


B.2. Пример значения UUIDv8 на основе имени

В соответствии с параграфом 5.5 UUID на основе имени с использованием современных алгоритмов хэширования должны создаваться в пространстве UUIDv8. Можно применять новые алгоритмы, такие как SHA-256 или SHA-512 [FIPS180-4], SHA-3 или SHAKE [FIPS202] и даже алгоритмы, которые ещё не определены.

Namespace (DNS):       6ba7b810-9dad-11d1-80b4-00c04fd430c8
Name:                  www.example.com
----------------------------------------------------------------
SHA-256:
5c146b143c524afd938a375d0df1fbf6fe12a66b645f72f6158759387e51f3c8

Рисунок 28. Пример UUIDv8 SHA-256.


Вариант SHA-256 для расчёта SHA, показанный в Приложении A.4, приведён на рисунке 28 как иллюстративный пример. Создание основанного на имени UUIDv8 здесь выполняется по той же логике, которая описана в параграфе 5.5, но с использованием алгоритма SHA-256 вместо SHA-1.

Поля и их значения показаны на рисунке 29. Дополнительная иллюстрации подстановки битов ver и var, а также используемая и неиспользуемая части значения SHA-256 показаны на рисунке 30. Для алгоритмов защищённого хеширования, выдающих результат произвольного размера (например, SHAKE) важно подчеркнуть, что их выход должен быть не менее 128 битов.

-------------------------------------------
поле     биты  значение
-------------------------------------------
custom_a  48   0x5c146b143c52
ver        4   0x8
custom_b  12   0xafd
var        2   0b10
custom_c  62   0b01, 0x38a375d0df1fbf6
-------------------------------------------
total     128
-------------------------------------------
final: 5c146b14-3c52-8afd-938a-375d0df1fbf6

Рисунок 29. Пример UUIDv8 SHA-256 на основе имени.

A: 5c146b14-3c52-4afd-938a-375d0df1fbf6-fe12a66b645f72f6158759387e51f3c8
B: xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
C: 5c146b14-3c52-8afd-938a-375d0df1fbf6
D:                                     -fe12a66b645f72f6158759387e51f3c8

Рисунок 30. Пример UUIDv8 с подстановкой Ver/Var и отбрасыванием сегмента SHA-256.


На рисунке 30:

  • строка A содержит полное значение SHA-256 в шестнадцатеричном формате с разделителями (0);

  • строка B показывает позиции полей ver и var, которые должны быть переписаны;

  • в строке C приведено значение после установки битов ver и var;

  • в строке D показана отбрасываемая часть битов исходного значения SHA-256.

Благодарности

Авторы с благодарностью отмечают вклад Rich Salz, Michael Mealling, Ben Campbell, Ben Ramsey, Fabio Lima, Gonzalo Salgueiro, Martin Thomson, Murray S. Kucherawy, Rick van Rein, Rob Wilton, Sean Leonard, Theodore Y. Ts“o, Robert Kieffer, Sergey Prokhorenko, LiosK, а также всех участников сообщества IETF и GitHub, участвовавших в обсуждении этого документа.

Документ в значительной степени основан на спецификации OSF DCE (Приложение A к [C309]) для UUID. Полезные замечания были получены от Ted Ts“o.

Спасибо Ralf S. Engelschall, John Larmouth, Paul Thorpe за внимательное прочтение и доработку материала. Профессор Larmouth внёс неоценимый вклад при согласовании с ISO/IEC.

Адреса авторов

Kyzer R. Davis

Cisco Systems

Email: kydavis@cisco.com

Brad G. Peabody

Uncloud

Email: brad@peabody.io

Paul J. Leach

University of Washington

Email: pjl7@uw.edu


Перевод на русский язык

Николай Малых

nmalykh@protokols.ru

1Internet Engineering Task Force — комиссия по решению инженерных задач Internet.

2Internet Engineering Steering Group — комиссия по инженерным разработкам Internet.

3Media Access Control — управление доступом к среде.

4В оригинале ошибочно указано 0, см. https://www.rfc-editor.org/errata/eid7958. Прим. перев.

5В оригинале ошибочно сказано «младших», см. https://www.rfc-editor.org/errata/eid7955. Прим. перев.

6В оригинале ошибочно указано 5623, см. https://www.rfc-editor.org/errata/eid8288. Прим. перев.

7В оригинале ошибочно указана таблица 1, см. https://www.rfc-editor.org/errata/eid8695. Прим. перев.

Запись опубликована в рубрике RFC. Добавьте в закладки постоянную ссылку.

Добавить комментарий