Когда вы действительно вынуждены использовать UUID как часть дизайна?

StackOverflow https://stackoverflow.com/questions/703035

  •  22-08-2019
  •  | 
  •  

Вопрос

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

Может кто-нибудь привести пример, когда у вас нет выбора, кроме как использовать UUID?Из всех применений, которые я видел, я вижу альтернативный дизайн без UUID.Конечно, конструкция может быть немного сложнее, но, по крайней мере, у нее нет ненулевой вероятности отказа.

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

Это было полезно?

Решение

Я написал генератор / синтаксический анализатор UUID для Ruby, поэтому считаю себя достаточно хорошо информированным по этому вопросу.Существует четыре основные версии UUID:

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

Идентификаторы UUID версий 5 и 3 используют хэш-функции SHA1 и MD5 соответственно, чтобы объединить пространство имен с частью уже уникальных данных для создания UUID.Это, например, позволит вам создать UUID из URL-адреса.Коллизии здесь возможны только в том случае, если базовая хэш-функция также имеет коллизию.

UUID версии 1 являются наиболее распространенными.Они используют MAC-адрес сетевой карты (который, если его не подделать, должен быть уникальным), плюс временную метку, плюс обычное изменение битов для генерации UUID.В случае компьютера, у которого нет MAC-адреса, 6 узловых байтов генерируются с помощью криптографически защищенного генератора случайных чисел.Если два UUID генерируются последовательно достаточно быстро, чтобы временная метка совпадала с предыдущим UUID, временная метка увеличивается на 1.Столкновения не должны возникать, если не произойдет одно из следующих событий:MAC-адрес подделан;Одна машина, на которой запущены два разных приложения, генерирующих UUID, выдает UUID в один и тот же момент;Двум машинам без сетевой карты или без доступа на уровне пользователя к MAC-адресу присваивается одна и та же случайная последовательность узлов, и они генерируют UUID в один и тот же момент;У нас заканчиваются байты для представления метки времени и отката обратно к нулю.

Реально, ни одно из этих событий не происходит случайно в пределах пространства идентификаторов одного приложения.Если вы не принимаете идентификаторы, скажем, в масштабах всего Интернета или в ненадежной среде, где злоумышленники могут сделать что-то плохое в случае столкновения идентификаторов, вам просто не о чем беспокоиться.Важно понимать, что если вам случится сгенерировать тот же UUID версии 4, что и мне, в большинстве случаев это не имеет значения.Я сгенерировал идентификатор в совершенно другом пространстве идентификаторов, отличном от вашего.Мое приложение никогда не узнает о столкновении, так что столкновение не имеет значения.Откровенно говоря, в едином пространстве приложений без злоумышленников исчезновение всей жизни на земле произойдет задолго до того, как у вас возникнет коллизия, даже для UUID версии 4, даже если вы генерируете довольно много UUID в секунду.

Кроме того, 2 ^ 64 * 16 - это 256 экзабайт.Например, вам нужно было бы сохранить идентификаторы объемом 256 экзабайт, прежде чем у вас появится 50%-ная вероятность столкновения идентификаторов в одном пространстве приложения.

Другие советы

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

Я читал, что в соответствии с парадоксом дня рождения вероятность возникновения столкновения UUID составляет 50% после генерации 2 ^ 64 UUID.Теперь 2 ^ 64 - довольно большое число, но 50%-ная вероятность столкновения кажется слишком рискованной (например, сколько UUID должно существовать, прежде чем появится 5%-ная вероятность столкновения - даже это кажется слишком большой вероятностью).

Проблема с этим анализом двоякая:

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

  2. строго говоря, UUID должны быть уникальными только среди набора других UUID, с которыми их можно сравнить.Если вы генерируете UUID для использования в качестве ключа базы данных, не имеет значения, используется ли где-нибудь еще в злой альтернативной вселенной тот же UUID для идентификации COM-интерфейса.Точно так же, как не вызовет путаницы, если на Альфе Центавра есть кто-то (или что-то) еще по имени "Майкл Берр".

Все имеет ненулевую вероятность неудачи.Я бы сосредоточился на гораздо более вероятных проблемах (т.е.почти все, что вы можете придумать), чем столкновение UUIDS

Акцент на "разумно" или, как вы выразились, "эффективно".:достаточно хорошо - это то, как устроен реальный мир.Объем вычислительной работы, необходимой для покрытия этого разрыва между "практически уникальным" и "по-настоящему уникальным", огромен.Уникальность - это кривая с убывающей отдачей.В какой-то момент на этой кривой проходит грань между тем, где "достаточно уникальный" все еще доступен по цене, а затем мы делаем ОЧЕНЬ крутой вираж.Стоимость добавления большей уникальности становится довольно большой.Бесконечная уникальность имеет бесконечную стоимость.

UUID / GUID - это, условно говоря, быстрый и простой в вычислительном отношении способ генерации идентификатора, который может быть разумно предполагается, что он универсально уникален.Это очень важно во многих системах, которым необходимо интегрировать данные из ранее не подключенных систем.Например:если у вас есть система управления контентом, которая работает на двух разных платформах, но в какой-то момент вам необходимо импортировать контент из одной системы в другую.Вы не хотите, чтобы идентификаторы менялись, поэтому ваши ссылки между данными из системы A остаются неизменными, но вы не хотите никаких столкновений с данными, созданными в системе B.UUID решает эту проблему.

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

Это может помочь в разрешении репликации базы данных и т.д...

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

В любом случае, несколько слов о вероятности столкновения, взятых из Википедии:

Чтобы представить эти цифры в перспективе, ежегодный риск попадания метеорита в человека оценивается как один шанс на 17 миллиардов, эквивалентный к шансам создать несколько десятков триллионов UUID за год и иметь один дубликат.Другими словами, только после генерации 1 миллиарда UUID каждую секунду в течение следующих 100 лет вероятность создания всего одного дубликата будет составлять около 50%.

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

Тебя это беспокоит?

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

DB(A) вставляет запись с идентификатором int 10 и в то же время DB(B) создает запись с идентификатором in 10.Это столкновение.

С UUID этого не произойдет, так как они не будут совпадать.(почти наверняка)

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

За исключением того, что с этим связаны некоторые реальные практические проблемы, даже если мы проигнорируем откровенную злобу.В частности, этот сервер может выйти из строя или стать недоступным из части Интернета.Устранение сбоя сервера требует репликации, и это очень трудно чтобы сделать все правильно (смотрите литературу по алгоритму Paxos о том, почему достижение консенсуса является неудобным) и к тому же довольно медленным.Более того, если все серверы недоступны из определенной части "сети, Нет клиенты, подключенные к этой подсети, смогут делать все, что угодно, потому что все они будут ждать новых идентификаторов.

Итак...используйте простой вероятностный алгоритм для их генерации, который вряд ли выйдет из строя в течение срока службы Земли, или (финансируйте и) постройте крупную инфраструктуру, которая будет представлять собой PITA развертывания и иметь частые сбои.Я знаю, на какой из них я бы остановил свой выбор.

Если вы просто посмотрите на альтернативы, напримердля простого приложения базы данных, которому приходится каждый раз запрашивать базу данных перед созданием нового объекта, вы скоро обнаружите, что использование UUID может эффективно снизить сложность вашей системы.Предоставлено - если вы используете ключи int, они будут 32-битными, в которых будет храниться четверть 128-битного UUID.Предоставлено - алгоритмы генерации UUID занимают больше вычислительной мощности, чем простое увеличение числа.Но - кого это волнует?Накладные расходы на управление "полномочиями" для присвоения уникальных номеров, в противном случае, легко перевешивают это на порядки, в зависимости от вашего предполагаемого пространства идентификаторов уникальности.

На UUID== ленивый дизайн

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

я не понимаю всех разговоров о вероятности столкновения.Меня не волнует столкновение.Однако я забочусь о производительности.

https://dba.stackexchange.com/a/119129/33649

UUID - это катастрофа производительности для очень больших таблиц.(200 ТЫСЯЧ строк - это не "очень большой".)

Ваш # 3 действительно плох, когда набор символов равен utf8 -- CHAR(36) занимает 108 байт!

UUID (GUID) очень "случайны".Используя их либо как УНИКАЛЬНЫЕ, либо как ПЕРВИЧНЫЙ ключ для больших таблиц очень неэффективен.Это связано с необходимостью перемещаться по таблице / индексу каждый раз, когда вы вставляете новый UUID или ВЫБЕРИТЕ по UUID.Когда таблица / индекс слишком велики, чтобы поместиться в кеш (смотрите innodb_buffer_pool_size, который должен быть меньше оперативной памяти, обычно 70%), "следующий" UUID может не кэшироваться, отсюда медленный диск попадание.Когда таблица / индекс в 20 раз больше кэша, только 1/20 (5%) обращений кэшируются - вы привязаны к вводу-выводу.

Итак, не используйте UUID, если только либо

у вас есть "маленькие" таблицы, или они вам действительно нужны из-за генерации уникальных идентификаторов из разных мест (и вы не придумали другого способа сделать это).Подробнее об UUIDS: http://mysql.rjweb.org/doc.php/uuid (Это включает функции для преобразования между стандартными 36-символьными UUID и ДВОИЧНЫЙ код (16).)

Наличие как УНИКАЛЬНОГО AUTO_INCREMENT, так и УНИКАЛЬНОГО UUID в одной и той же таблице является пустой тратой времени.

Когда происходит ВСТАВКА, все уникальные / первичные ключи должны быть проверены на наличие дубликатов.Любой уникальный ключ достаточен для требования InnoDB о наличии ПЕРВИЧНОГО КЛЮЧА.ДВОИЧНЫЙ файл (16) (16 байт) несколько громоздок ( аргумент против превращения его в PK), но не так уж плох.Громоздкость имеет значение, когда у вас есть дополнительные ключи.InnoDB автоматически прикрепляет PK к концу каждого вторичного ключа.Основной урок здесь заключается в том, чтобы свести к минимуму количество вторичных ключей, особенно для очень больших таблицы.Для сравнения:INT UNSIGNED - это 4 байта с диапазоном 0 ..4 миллиард.BIGINT - это 8 байт.

На моей последней работе мы получали объекты от третьих сторон, которые были однозначно идентифицированы с помощью UUID.Я ввел таблицу поиска UUID-> long integer и использовал long integer в качестве первичных ключей, потому что так было намного быстрее.

Используя алгоритм версии 1, кажется, что столкновение невозможно при ограничении того, что с одного и того же MAC-адреса генерируется менее 10 UUID в миллисекунду

Концептуально оригинал (версия 1) схема генерации для UUID заключалась в том, чтобы объединить версию UUID с MAC-адрес компьютера, который генерирует UUID, и с количеством интервалов в 100 наносекунд с момента принятия григорианского календаря на Западе.На практике реальный алгоритм более сложный.Эта схема подверглась критике в за то, что она недостаточно "непрозрачна";он раскрывает как идентификатор компьютера, который сгенерировал UUID, так и время, в которое он это сделал.

Кто-нибудь, поправьте меня, если я неправильно истолковал, как это работает

Для тех, кто говорит, что UUID - это плохой дизайн, потому что они мог бы (с некоторой смехотворно малой вероятностью) столкнутся, в то время как сгенерированные вашей БД ключи этого не сделают...вы знаете, что вероятность человеческой ошибки, вызвавшей коллизию сгенерированных ключей вашей базы данных из-за какой-то непредвиденной необходимости, НАМНОГО, НАМНОГО выше, чем вероятность коллизии UUID4.Мы знать что если база данных будет воссоздана, она снова начнет использовать ids с 1, а скольким из нас приходилось воссоздавать таблицу, когда мы были уверены, что нам это никогда не понадобится?Я бы поставил свои деньги на безопасность UUID, когда в любой день что-то начинает идти не так с неизвестными-unknowns.

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

Да, теоретически возможно, что UUID столкнутся.Как отмечали другие, это до смешного маловероятно до такой степени, что об этом просто не стоит задумываться.Такого никогда не случалось на сегодняшний день и, скорее всего, никогда не будет.Забудь об этом.

Самый "очевидный" способ избежать коллизий - позволить одному серверу генерировать уникальные идентификаторы при каждой вставке, что, очевидно, создает серьезные проблемы с производительностью и вообще не решает проблему автономной генерации.Упс.

Другим "очевидным" решением является центральный орган, который заранее раздает блоки уникальных номеров, что, по сути, и делает UUID V1, используя MAC-адрес генерирующей машины (через IEEE OUI).Но дублирующиеся MAC-адреса действительно случаются, потому что каждый центральный орган рано или поздно облажается, так что на практике это гораздо более вероятно, чем коллизия UUID V4.Упс.

Лучшим аргументом против использования UUID является то, что они "слишком большие", но (значительно) меньшая схема неизбежно не сможет решить самые интересные проблемы;Размер UUID является неотъемлемым побочным эффектом их полезности при решении тех самых проблем.

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top