Я знаю, что рандомизированные UUID имеют очень, очень, очень низкую вероятность коллизии в теории, но мне интересно, на практике, насколько хорош Java randomUUID()
с точки зрения отсутствия коллизии? У кого-нибудь есть опыт, которым можно поделиться?
Насколько хороша Java UUID.randomUUID?
Ответ 1
UUID использует java.security.SecureRandom
, который должен быть "криптографически сильным". Хотя фактическая реализация не указана и может варьироваться между JVM (это означает, что любые конкретные сделанные заявления действительны только для одной конкретной JVM), она гарантирует, что выход должен пройти статистический тест генератора случайных чисел.
Всегда возможно, чтобы реализация содержала тонкие ошибки, которые разрушают все это (см. ошибку генерации ключей OpenSSH), но я не думаю, что есть какая-то конкретная причина беспокоиться о случайности Java UUID.
Ответ 2
Википедия имеет очень хороший ответ http://en.wikipedia.org/wiki/Universally_unique_identifier#Collisions
количество случайных версий 4 UUID, которые должны быть сгенерированы для того, чтобы иметь 50% вероятность хотя бы одного столкновения, составляет 2,71 квинтиллиона, рассчитывается следующим образом:
...
Это число эквивалентно генерации 1 миллиарда UUID в секунду в течение примерно 85 лет, а файл, содержащий это множество UUID, по 16 байт на UUID, будет составлять около 45 экзабайт, во много раз больше, чем самые большие в настоящее время базы данных, которые составляют порядка сотен петабайт.
...
Таким образом, для того, чтобы существовать один из миллиардов шансов на дублирование, необходимо создать 103 триллиона UUID версии 4.
Ответ 3
У кого-нибудь есть опыт, которым можно поделиться?
Есть 2^122
возможных значений для UUID типа 4. (В спецификации сказано, что вы теряете 2 бита для типа и еще 4 бита для номера версии.)
Предполагая, что вы должны были генерировать 1 миллион случайных UUID в секунду, шансы дублирования в вашей жизни были бы крайне малы. И чтобы обнаружить дубликаты, вам нужно решить задачу сравнения 1 миллиона новых UUID в секунду со всеми UUID, которые вы сгенерировали ранее 1 !
Вероятность того, что кто-либо испытал (то есть действительно заметил) дубликат в реальной жизни, даже меньше, чем исчезающе мала... из-за практической трудности поиска столкновений.
Теперь, конечно, вы, как правило, будете использовать генератор псевдослучайных чисел, а не источник действительно случайных чисел. Но я думаю, мы можем быть уверены, что если вы используете надежного провайдера для вашей криптографической силы случайных чисел, то это будет криптографическая сила, и вероятность повторов будет такой же, как для идеального (не смещенного) генератора случайных чисел,
Однако если вы используете JVM с "сломанным" генератором случайных чисел crypto-, все ставки отключены. (И это может включать некоторые обходные пути для проблем "нехватки энтропии" в некоторых системах. Или вероятность того, что кто-то возился с вашей JRE, либо в вашей системе, либо в восходящем направлении.)
1 - Предполагая, что вы использовали "некое двоичное btree", как предложено анонимным комментатором, каждому UUID потребуется O(NlogN)
битов оперативной памяти для представления N
различных UUID, предполагающих низкую плотность и случайное распределение битов.Теперь умножьте это на 1 000 000 и количество секунд, для которых вы собираетесь запустить эксперимент.Я не думаю, что это практично в течение периода времени, необходимого для проверки на столкновения высококачественного ГСЧ.Даже с (гипотетическими) умными представлениями.
Ответ 4
Я не эксперт, но я бы предположил, что достаточно умные люди смотрели на генератор случайных чисел Java на протяжении многих лет. Следовательно, я также предполагаю, что случайные UUID являются хорошими. Поэтому у вас действительно должна быть теоретическая вероятность столкновения (примерно 1: 3 × 10 ^ 38 для всех возможных UUID. Кто-нибудь знает, как это изменяется для случайных UUID только? Это 1/(16*4)
из вышеперечисленного?)
Из моего практического опыта я до сих пор не видел никаких столкновений. Вероятно, у меня, наверное, была удивительно длинная борода в тот день, когда я получу свой первый;)
Ответ 5
Первоначальная схема генерации UUID заключалась в объединении версии UUID с MAC-адресом компьютера, который генерирует UUID, и с числом 100-наносекундных интервалов с момента принятия григорианского календаря на Западе. Представляя единую точку в пространстве (компьютер) и время (количество интервалов), вероятность столкновения в значениях фактически равна нулю.
Ответ 6
У бывшего работодателя у нас был уникальный столбец, содержащий случайный uuid. Мы столкнулись с первой неделей после ее развертывания. Конечно, шансы низкие, но они не равны нулю. Вот почему Log4j 2 содержит UuidUtil.getTimeBasedUuid. Он будет генерировать UUID, который уникален в течение 8 925 лет, если вы не генерируете более 10 000 UUID/миллисекунд на одном сервере.
Ответ 7
Многие из ответов обсуждают, сколько UUID должно быть создано для достижения 50% -ной вероятности столкновения. Но вероятность столкновения 50%, 25% или даже 1% бесполезна для приложения, где столкновение должно быть (практически) невозможным.
Прописывают ли программисты регулярное отклонение как "невозможное" других событий, которые могут и происходят?
Когда мы записываем данные на диск или в память и читаем их снова, мы считаем само собой разумеющимся, что данные верны. Мы полагаемся на исправление ошибок устройства, чтобы обнаружить любое повреждение. Но вероятность необнаруженных ошибок на самом деле составляет около 2 -50.
Не имеет ли смысл применять аналогичный стандарт для случайных UUID? Если вы это сделаете, вы обнаружите, что "невозможное" столкновение возможно в коллекции около 100 миллиардов случайных UUID (2 36,5).
Это астрономическое число, но приложения, такие как подробное выставление счетов в национальной системе здравоохранения или регистрация данных высокочастотных датчиков на большом массиве устройств, могут определенно столкнуться с этими ограничениями. Если вы пишете следующее руководство для автостопом по Галактике, не пытайтесь присваивать UUID каждой статье!
Ответ 8
Я играю в лотерею в прошлом году, и я никогда не выигрывал.... но похоже, что в лотерее есть победители...
документ: http://tools.ietf.org/html/rfc4122
Тип 1: не реализовано. Коллизия возможно, если UUID генерируется в тот же момент. impl может быть искусственно синхронизирован, чтобы обойти эту проблему.
Тип 2: никогда не видеть реализацию.
Тип 3: хэш md5: возможна коллизия (128 бит-2 технических байтов)
Тип 4: случайный: возможно коллизия (как лотерея). обратите внимание, что в jdk6 не используется "истинное" безопасное случайное число, потому что разработчик не выбирает алгоритм PRNG, и вы можете заставить систему использовать "плохой" алгоритм PRNG. Так что ваш UUID предсказуем.
Тип 5: хэш sha1: не реализовано: возможно коллизия (160 бит-2 технических байтов)
Ответ 9
Так как большинство ответов были сосредоточены на теории, я думаю, что я могу кое-что добавить к обсуждению, дав практический тест, который я сделал. В моей базе данных около 4,5 миллионов UUID, сгенерированных с помощью Java 8 UUID.randomUUID(). Следующие - только некоторые, которые я узнал:
c0f55f62 -b990-47bc-8caa-f42313669948
c0f55f62 -e81e-4253-8299-00b4322829d5
c0f55f62 -4979-4e87-8cd9-1c556894e2bb
b9ea2498-fb32-40ef-91ef-0ba 00060fe64
be87a209-2114-45b3-9d5a-86d 00060fe64
4a8a74a6-e972-4069-b480-b dea1177b21f
12fb4958-bee2-4c89-8cf8-e dea1177b21f
Если бы это было действительно случайно, вероятность наличия подобных UUID такого рода была бы значительно ниже (см. Редактирование), поскольку мы рассматриваем только 4,5 миллиона записей. Так что, хотя эта функция хороша, с точки зрения отсутствия коллизий, для меня она не кажется такой хорошей, как это было бы в теории.
Редактировать:
Многие люди, похоже, не понимают этого ответа, поэтому я проясню свою точку зрения: я знаю, что сходства "малы" и далеки от полного столкновения. Однако я просто хотел сравнить Java UUID.randomUUID() с генератором истинных случайных чисел, что является актуальным вопросом.
В истинном генераторе случайных чисел вероятность возникновения последнего случая будет около = 0,007%. Поэтому я думаю, что мой вывод верен.
Формула объясняется в этой статье вики en.wikipedia.org/wiki/Birthday_problem
Ответ 10
Мы используем случайный UUID Java в нашем приложении более одного года, и это очень интенсивно. Но мы не сталкиваемся с столкновением.
Ответ 11
Если вы действительно хотите быть уверенным, что не будет абсолютно никакого столкновения, просто добавьте текущие миллисекунды с эпохи перед UUID-Строкой, например.
String id = System.currentTimeMillis() + "-" + UUID.randomUUID().toString();
Итак, чтобы иметь 50% вероятность столкновения за миллисекунду, вам нужно будет создать 2,71 квинтиллиона за одну миллисекунду, что очень, очень маловероятно!
Фактически, было бы относительно безопасно использовать некоторые из первых цифр UUID. Я проверил безопасность следующей строки:
String id = UUID.randomUUID().toString().substring(0, 6);
Я тестировал, сколько из этих строк мне нужно создать, чтобы получить столкновение. В среднем столкновение произойдет после создания порядка 5163 строк! Минимальное количество строк, которые мне нужно было создать для создания столкновения, было 53 (я тестировал его 100000 раз). Однако, если бы я хотел сделать тот же тест с строкой длиной 8, я бы даже не смог ее вычислить один раз (я дал ей 20мин времени).