Поиск по сайту:

Что такое UUID и почему они полезны?


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

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

Что такое UUID?

UUID — это просто значение, которое можно безопасно рассматривать как уникальное. Риск столкновения настолько низок, что вы можете разумно полностью его игнорировать. Вы можете видеть, что UUID упоминаются с использованием разных терминов (GUID или глобальный уникальный идентификатор — это предпочтительная семантика Microsoft), но смысл и эффект остаются прежними.

Истинный UUID — это уникальный идентификатор, сгенерированный и представленный в стандартизированном формате. Допустимые UUID определены в RFC 4122; в этой спецификации описываются алгоритмы, которые можно использовать для создания UUID, сохраняющих уникальность в разных реализациях, без центрального органа, выдавшего их.

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

  • Версия 1 – на основе времени – объединяет метку времени, последовательность часов и значение, характерное для генерирующего устройства (обычно его MAC-адрес), для создания вывода, уникального для этого хоста на этот момент времени.
  • Версия 2 — Безопасность DCE. Эта версия была разработана как развитие версии 1 для использования с распределенной вычислительной средой (DCE). Широко не используется.
  • Версия 3 — на основе имени (MD5) — MD5 хэширует «пространство имен» и «имя», чтобы создать значение, уникальное для этого имени в пределах пространства имен. Создание другого UUID с тем же пространством имен и именем приведет к идентичным результатам, поэтому этот метод обеспечивает воспроизводимые результаты.
  • Версия 4 – случайный – большинство современных систем, как правило, выбирают UUID v4, поскольку для выдачи значений он использует источник случайных или псевдослучайных чисел хоста. Вероятность того, что один и тот же UUID будет создан дважды, практически ничтожно мала.
  • Версия 5 – на основе имен (SHA-1) – похожа на версию 3, но использует более надежный алгоритм SHA-1 для хеширования входного пространства имен и имени.

Хотя в RFC алгоритмы называются версиями, это не означает, что вы всегда должны использовать версию 5, потому что она кажется самой новой. Выбор зависит от вашего варианта использования; во многих сценариях v4 выбирается из-за его случайного характера. Это делает его идеальным кандидатом для простых сценариев «дайте мне новый идентификатор».

Алгоритмы генерации выдают 128-битное целое число без знака. Однако UUID чаще всего рассматриваются как шестнадцатеричные строки, а также могут храниться в виде двоичной последовательности из 16 символов. Вот пример строки UUID:

16763be4-6022-406e-a950-fcd5018633ca

Значение представлено пятью группами буквенно-цифровых символов, разделенных тире. Дефисы не являются обязательным компонентом строки; их присутствие связано с историческими деталями спецификации UUID. Они также значительно облегчают восприятие идентификатора человеческим глазом.

Варианты использования UUID

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

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

Вот базовая демонстрация PHP, которая демонстрирует разницу. Давайте сначала посмотрим на целочисленную систему:

class BlogPost {
    public function __construct(
        public readonly ?int $Id,
        public readonly string $Headline,
        public readonly ?AuthorCollection $Authors=null) {}
}
 
#[POST("/posts")]
function createBlogPost(HttpRequest $Request) : void {
    $headline = $Request -> getField("Headline");
    $blogPost = new BlogPost(null, $headline);
}

Мы должны инициализировать свойство $Id с помощью null, потому что мы не можем знать его фактический идентификатор до тех пор, пока после он не будет сохранен в базе данных. Это не идеально — $Id на самом деле не должен принимать значение null, и это позволяет экземплярам BlogPost существовать в незавершенном состоянии.

Переход на UUID решает проблему:

class BlogPost {
    public function __construct(
        public readonly string $Uuid,
        public readonly string $Headline,
        public readonly ?AuthorCollection $Authors=null) {}
}
 
#[POST("/posts")]
function createBlogPost(HttpRequest $Request) : void {
    $headline = $Request -> getField("Headline");
    $blogPost = new BlogPost("16763be4-...", $headline);
}

Идентификаторы записей теперь можно генерировать в приложении, не рискуя дублировать значения. Это гарантирует, что экземпляры объекта всегда представляют допустимое состояние и не нуждаются в неуклюжих свойствах ID, допускающих значение null. Модель также упрощает обработку транзакционной логики; дочерние записи, которым нужна ссылка на их родителя (например, ассоциации Author нашего сообщения), могут быть вставлены немедленно, без обращения к базе данных для получения идентификатора, который был назначен родителю.

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

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

Предостережения, когда UUID встречаются с базами данных

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

Чего нельзя сказать об UUID. Начнем с того, что UUID в четыре раза больше, чем целые числа (36 байтов против 4 байтов); для больших наборов данных это само по себе может быть важным фактором. Значения также намного сложнее сортировать и индексировать, особенно в случае наиболее распространенных случайных UUID. Их случайный характер означает, что они не имеют естественного порядка. Это ухудшит производительность индексирования, если вы используете UUID в качестве первичного ключа.

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

Вы можете частично смягчить проблемы, сохранив свои UUID в виде двоичных данных. Это означает столбец BINARY(16) вместо VARCHAR(36). Некоторые базы данных, такие как PostgreSQL, включают встроенный тип данных UUID; другие, такие как MySQL, имеют функции, которые могут преобразовать строку UUID в ее двоичное представление и наоборот. Этот подход более эффективен, но помните, что вы все равно будете использовать дополнительные ресурсы для хранения и выбора данных.

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

Краткое содержание

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

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

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

Более очевидная проблема для большинства разработчиков связана с хранением и извлечением сгенерированных UUID. Наивное использование VARCHAR(36) (или удаление дефисов и использование VARCHAR(32)) может со временем нанести вред вашему приложению, поскольку большинство оптимизаций индексации базы данных будут неэффективными. Изучите встроенные возможности обработки UUID вашей системы баз данных, чтобы обеспечить максимально возможную производительность вашего решения.




Все права защищены. © Linux-Console.net • 2019-2024