Наскільки хороший UUID.randomUUID Java?


311

Я знаю, що рандомізовані UUID мають теоретичну дуже, дуже-дуже низьку ймовірність зіткнення, але мені цікаво на практиці, наскільки хороший Java в randomUUID()тому, що він не має зіткнення? Хтось має досвід поділитися?


10
З мого досвіду, я ніколи не бачив зіткнення ;-)
Тіло,

4
Алгоритми визначені в RFC1422: ietf.org/rfc/rfc4122.txt
skaffman

8
@skaffman: RFC не говорить абсолютно нічого про алгоритм, який використовується для генерування випадкових цифр.
Майкл Боргвардт

4
Оскільки це питання більш відкритого типу, я вважаю, що я не позначу відповідь правильною відповіддю; натомість я дам один голос на кожну з відповідей, які я вважаю гарними :)
Елвін,

5
З вікіпедії: ... Іншими словами, лише після генерування 1 мільярда UUID щосекунди протягом наступних 100 років ймовірність створення лише одного дубліката склала б приблизно 50%.
MaVRoSCy

Відповіді:


168

Використовується UUID java.security.SecureRandom, який повинен бути "криптографічно сильним". Хоча фактична реалізація не визначена і може змінюватись між JVM (мається на увазі, що будь-які конкретні заяви зроблені лише для одного конкретного JVM), вона наказує, що вихід повинен пройти тест статистичного генератора випадкових чисел.

Завжди можливо, що впровадження містить тонкі помилки, які все це руйнують (див. Помилку генерації ключів OpenSSH), але я не думаю, що є конкретні причини для занепокоєння щодо випадковості Java UUID.


34
"Завжди можливо, щоб реалізація містила тонкі помилки ..." - Або (надягаючи капелюх з олов'яної фольги) ... навмисні тонкі недоліки. <:-)
Стівен C

25
Сила криптографії абсолютно не має значення для питання зіткнень.
оса

14
@osa: Не створюючи зіткнень (більше, ніж очікувати від ідеальної випадковості) - це майже найнижча вимога до якості RNG, тоді як криптографічна сила - найвища. Іншими словами, криптографічно сильний RNG, безумовно, не спричинить більше зіткнень, ніж очікувалося.
Майкл Боргвардт

3
Це може бути корисно зауважити, що якщо ви, наприклад, запустите JVM, який вибиває UUID, всередині blogs.vmware.com/cto/… , ви, мабуть, отримаєте багато, багато зіткнень. Всі програмні RNG - це PRNG, і вони в кінцевому підсумку є настільки ж хорошими, як джерело ентропії; два PRNG, які сіяться однаково, також будуть поводитися однаково, і це може статися напрочуд часто при послідовних, точно повторюваних настройках сервера та процедурах запуску.
user508633

@ user508633: Я б фактично очікував отримати 100% коефіцієнт зіткнення в цьому конкретному випадку, але це дуже конкретний випадок, який дійсно виходить за рамки "послідовних, точних копій налаштувань сервера та процедур запуску". Я впевнений, що ви не отримаєте жодних підвищених частот зіткнень, якби ви просто клонували VM і запустили його нормально. Самосіття SecureRandom намагається досить важко отримати справжню ентропію, щоб заблокувати виконання, якщо воно не може знайти жодного: seancassidy.me/wiggle-the-mouse-to-fix-the-test.html
Michael Боргвардт

114

У Вікіпедії є дуже хороша відповідь http://en.wikipedia.org/wiki/Universally_unique_identifier#Collisions

кількість випадкових UUID версії 4, які необхідно генерувати для того, щоб мати 50% -ву ймовірність принаймні одного зіткнення, становить 2,71 квінтільйона, обчислюється так:

...

Це число еквівалентно генеруванню 1 мільярда UUID в секунду протягом приблизно 85 років, а файл, що містить це багато UUID, у 16 ​​байт на UUID, буде приблизно 45 екбабайтів, у багато разів більший, ніж найбільші бази даних, що існують зараз порядку сотень петабайт.

...

Таким чином, щоб не було шансів на дублювання одного мільярда, необхідно створити 103 трильйони UUID версії 4.


56
Я також цитую на цій сторінці: "Ймовірність одного дубліката складе близько 50%, якщо кожна людина на землі має 600 мільйонів UUID".
Джефф Аксельрод

24
Це справедливо лише для справжньої випадковості, а не для псевдовипадкових чисел, таких як javas UUID.
Маркус

9
@Markus: абсолютно неправильно. Ймовірність зіткнень для хороших псевдовипадкових РНГ, особливо криптографічно сильних, не відрізняється від "справжньої" випадковості.
Майкл Боргвардт

6
@Eric - Я думаю, що на вас стоїть думка, щоб підкріпити своє твердження. FWIW, єдиний сценарій, який я можу придумати, де стикаються UUID типу 4 частіше, оскільки теорія ймовірностей стверджує, що це: 1) поганий джерело криптовалютних випадкових чисел, або 2) бібліотека UUID, яка була порушена.
Стівен С

13
Це не відповідає на поставлене запитання. Питання полягає у якості випадкових випадків у Java UUID.randomUUID(), а не в теоретичних шансах для даного ідеального генератора випадкових чисел.
kratenko

69

Хтось має досвід поділитися?

Існують 2^122можливі значення для UUID типу-4. (Специфікація говорить про те, що ви втрачаєте 2 біти для типу та ще 4 біти для номера версії.)

Якщо припустити, що ви повинні генерувати 1 мільйон випадкових UUID в секунду, шанси появи дубліката у вашому житті були б малі малі. А щоб виявити дублікат, вам доведеться вирішити проблему порівняння 1 мільйона нових UUID в секунду проти всіх UUID, які ви раніше генерували 1 !

Шанси, що хтось відчув (тобто насправді помітив ) дублікат у реальному житті, навіть менші, ніж зникаючі малі ... через практичні труднощі пошуку зіткнень.

Звичайно, ви, як правило, використовуєте генератор псевдовипадкових чисел, а не джерело справді випадкових чисел. Але я думаю, ми можемо бути впевнені, що якщо ви використовуєте надійного постачальника для своїх криптографічних силових випадкових чисел, то це буде криптографічна сила, а ймовірність повторів буде такою ж, як і для ідеального (не упередженого) генератора випадкових чисел .

Однак якщо ви користувались JVM із "зламаним" генератором крипто-випадкових чисел, усі ставки виключаються. (І це може включати деякі шляхи вирішення проблем "дефіциту ентропії" в деяких системах. Або можливість того, що хтось пограбував із вашим JRE, або у вашій системі, або вище за течією.)


1 - Якщо припустити, що ви використовували "якусь бінарну btree", запропоновану анонімним коментатором, кожному UUID знадобляться O(NlogN)біти оперативної пам'яті, щоб представляти Nрізні UUID, припускаючи низьку щільність і випадковий розподіл бітів. Тепер помножте це на 1 000 000 і кількість секунд, для яких ви збираєтеся запустити експеримент. Я не думаю, що це практично для тривалості часу, необхідного для тестування на зіткнення високоякісної РНГ. Навіть з (гіпотетичними) розумними уявленнями.


4
"(А щоб виявити дублікат, вам доведеться вирішити проблему порівняння 1 мільйона нових UUID в секунду проти всіх створених раніше UUID!)" - ця частина відносно проста, якщо припустити, що ви зберігали свої удеїди в деяких якась двійкова структура дерева, це було б просто спуск одного дерева за нову уюїду. Вам не потрібно було б фактично порівнювати його окремо з усіма створеними раніше удами.
user467257

20

Я не фахівець, але припускаю, що достатньо розумних людей за ці роки дивився генератор випадкових чисел Java. Отже, я також припускаю, що випадкові UUID є хорошими. Таким чином, ви дійсно повинні мати теоретичну ймовірність зіткнення (що становить приблизно 1: 3 × 10 ^ 38 для всіх можливих UUID. Хто-небудь знає, як це змінюється лише для випадкових UUID? Це 1/(16*4)вищезазначене?)

Зі свого практичного досвіду я досі не бачив жодних зіткнень. Я, мабуть, виростив приголомшливо довгу бороду того дня, коли отримаю свою першу;)


10
З вікіпедії: ... Іншими словами, лише після генерування 1 мільярда UUID щосекунди протягом наступних 100 років ймовірність створення лише одного дубліката склала б приблизно 50%.
MaVRoSCy

1
Насправді вікіпедія говорить, що це буде протягом наступних 85 років ... Я кажу, що не розраховуйте на це, хтось десь створив такий же UUID, як і ви
smac89

12

У колишнього роботодавця ми мали унікальну колонку, яка містила випадковий uuid. У нас відбулося зіткнення перший тиждень після його розгортання. Звичайно, шанси низькі, але вони не нульові. Ось чому Log4j 2 містить UuidUtil.getTimeBasedUuid. Він генерує UUID, який є унікальним протягом 8 925 років, якщо ви не генеруєте більше 10 000 UUID / мілісекунд на одному сервері.


2
Так. Але питання полягає у випадкових (тобто тип-4) UUID.
Стівен С

1
Це питання про ймовірність отримати зіткнення. Це означає, що він хоче бути впевненим, щоб їх уникнути.
rgoers

1
(Зіткнення, швидше за все, було пов’язане з зламаним джерелом випадковості висіву PRNG. Я гадаю, що можливо, це було через чистий шанс.)
Stephen C

9

Початкова схема покоління для UUID полягала у поєднанні версії UUID з MAC-адресою комп'ютера, що генерує UUID, та з кількістю інтервалів 100 наносекунд з моменту прийняття григоріанського календаря на Заході. Представляючи єдину точку в просторі (комп'ютер) і часу (кількість інтервалів), шанс зіткнення значень фактично нульовий.


1
Це пояснення змушує мене оптимістично не бачити зіткнень на практиці. Чи можете ви вказати на будь-яку посилання на це твердження (якийсь вихідний код був би ще кращим)?
Драган Мар’янович

Знайдено це в специфікаціях ietf.org/rfc/rfc4122.txt . Тим не менш, було б здорово побачити реалізацію.
Драган Мар’янович

1
Однак ця схема не є реалізованою Java. Java реалізує UUID типу 4, що є випадковим випадком і не включає MAC-адресу або час. Між іншим, оскільки зараз існує багато фізичних та віртуальних пристроїв, на яких можна вибрати свою MAC-адресу, оригінальний алгоритм не гарантує унікальності.
Søren Boisen

8

Багато відповідей обговорюють, скільки UUID повинні створити для досягнення 50% шансу зіткнення. Але 50%, 25%, а то й 1% шанс зіткнення марний для програми, коли зіткнення має бути (практично) неможливим.

Чи програмісти звичайно відкидають як "неможливі" інші події, які можуть і можуть відбутися?

Коли ми записуємо дані на диск або пам'ять і читаємо їх знову, ми вважаємо належними дані, що вони є правильними. Ми розраховуємо на виправлення помилок пристрою, щоб виявити будь-які пошкодження. Але ймовірність виявлення помилок насправді близько 2 -50 .

Чи не було б сенсу застосовувати подібний стандарт до випадкових UUID? Якщо ви це зробите, ви виявите, що "неможливе" зіткнення можливе в колекції близько 100 мільярдів випадкових UUID (2 36,5 ).

Це астрономічне число, але такі програми, як деталізовані рахунки в національній системі охорони здоров’я або введення даних високочастотних датчиків на великий масив пристроїв, безумовно, можуть натрапити на ці межі. Якщо ви пишете наступне керівництво автостопом до Галактики, не намагайтеся призначити UUID для кожної статті!


Для порівняння, шанс виграти джекпот Powerball становить 1 на 300 мільйонів, але продажі квитків від 10 до 20 мільйонів є типовими. Справа в тому, що багато людей визначають "неможливе" як щось менше, ніж один шанс у сотнях мільйонів.
еріксон

4

Оскільки більшість відповідей зосереджені на теорії, я думаю, що я можу щось додати до дискусії, давши практичний тест, який я зробив. У моїй базі даних є близько 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%. Тому я думаю, що мій висновок стоїть.

Формула пояснюється в цій статті wiki en.wikipedia.org/wiki/Birthday_problem


6
Це не правда. Подібне подібне виникне навіть у справжньому генераторі випадкових чисел на 4,5-метрових уйдах. Подібність між виданими вами UUID невелика і далека, о, поки що не повне зіткнення.
користувач3711864

Я повністю погоджуюся з вами, що подібність "мала" і далеко не повне зіткнення. Однак я просто хотів порівняти Java UUID.randomUUID () з справжнім генератором випадкових чисел (це питання). За деякими підрахунками ми бачимо, що в справжньому генераторі випадкових чисел вірогідність того, що відбудеться останній випадок, буде приблизно 1-e ^ (- 4500000 ^ 2 / (2 * 36 ^ 11)) = 0,007% = 1 в 13 к. Мені б дуже пощастило :)
Андре Піньєро

1
З 4,5 мільйонами предметів і шансом 1 на 13 к, чи не очікується часткове зіткнення, як це, 346 разів?
Бен Лі

Ні @BenLee, я підрахував вірогідність того, що ця подія станеться, враховуючи, що у нас 4,5 мільйона предметів. Це не шанс 1 на 13 к для кожного предмета. Формулу, яку я використав, можна знайти в цій статті вікі en.wikipedia.org/wiki/Birthday_problem
Андре Піньєро

2
Що було вашим сподіванням? Подібне не те саме, чи не так?
Корай Тугай

3

Я грав на лотереї минулого року, і ніколи не вигравав .... але, схоже, там лотерея має переможців ...

doc: http://tools.ietf.org/html/rfc4122

Тип 1: не реалізовано. зіткнення можливе, якщо uuid генерується в той же момент. impl можна штучно синхронізувати, щоб обійти цю проблему.

Тип 2: ніколи не бачити реалізацію.

Тип 3: хеш md5: можливе зіткнення (128 біт-2 технічні байти)

Тип 4: випадковий: можливе зіткнення (як лотерея). зауважте, що jdk6 impl не використовує "справжній" захищений випадковий випадок, оскільки алгоритм PRNG не вибирається розробником, і ви можете змусити систему використовувати "поганий" PRNG algo. Тож ваш UUID передбачуваний.

Тип 5: хеш sha1: не реалізовано: можливе зіткнення (160 біт-2 технічні байти)


4
Ймовірність виграти в лотерею, можливо, один з 10 або 100 мільйонів (10 ^ 7 або 10 ^ 8) або щось подібне. Імовірність зіткнення зі 128-бітовим випадковим числом становить 3,4 * 10 ^ 28. Дайте мені лотерейний квиток будь-коли!
Стівен С

0

Ми використовуємо випадковий UUID Java у нашому додатку вже не один рік, і це дуже широко. Але нам ніколи не трапляється зіткнення.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.