Quanto è buono UUID.randomUUID di Java?


311

So che gli UUID randomizzati hanno una probabilità molto, molto, molto bassa di collisione in teoria, ma mi chiedo, in pratica, quanto è buono Java randomUUID()in termini di non avere collisioni? Qualcuno ha qualche esperienza da condividere?


10
Nella mia esperienza, non ho mai visto una collisione ;-)
Thilo

4
Gli algoritmi sono specificati in RFC1422: ietf.org/rfc/rfc4122.txt
skaffman

8
@skaffman: RFC non dice assolutamente nulla sull'algoritmo utilizzato per generare cifre casuali.
Michael Borgwardt,

4
Dal momento che questa è una domanda più aperta, suppongo che non segnerò nessuna risposta come la risposta corretta; darò invece un voto a ciascuna delle risposte che ritengo positive :)
Alvin,

5
Da Wikipedia: ... In altre parole, solo dopo aver generato 1 miliardo di UUID ogni secondo per i prossimi 100 anni, la probabilità di creare un solo duplicato sarebbe di circa il 50%.
MaVRoSCy,

Risposte:


168

UUID utilizza java.security.SecureRandom, che dovrebbe essere "crittograficamente forte". Sebbene l'implementazione effettiva non sia specificata e possa variare tra le JVM (il che significa che tutte le dichiarazioni concrete fatte sono valide solo per una JVM specifica), richiede che l'output debba superare un test statistico di generazione di numeri casuali.

È sempre possibile che un'implementazione contenga dei bug sottili che rovinano tutto questo (vedi bug di generazione delle chiavi di OpenSSH) ma non penso che ci siano ragioni concrete per preoccuparsi della casualità degli UUID Java.


34
"È sempre possibile che un'implementazione contenga dei bug sottili ..." - O (indossando un cappello di lamina di metallo) ... sottili difetti deliberati. <:-)
Stephen C,

25
La forza crittografica è completamente irrilevante per la questione delle collisioni.
Oosa,

14
@osa: non produrre collisioni (più di quanto ci si possa aspettare dalla perfetta casualità) è praticamente il requisito di qualità più basso per un RNG, mentre la forza crittografica è la più alta. In altre parole, un RNG crittograficamente forte non produrrà sicuramente più collisioni del previsto.
Michael Borgwardt,

3
Potrebbe essere utile notare, tuttavia, che se ad esempio esegui una JVM sfornando UUID all'interno di blogs.vmware.com/cto/… , probabilmente otterrai molte, molte collisioni. Tutti gli RNG software sono PRNG e alla fine sono validi solo come la loro fonte di entropia; due PRNG che vengono seminati in modo identico si comportano in modo identico e ciò può accadere sorprendentemente spesso con configurazioni del server e procedure di avvio coerenti, esattamente duplicate.
user508633

@ user508633: Mi aspetterei in realtà di ottenere una percentuale di collisione del 100% in quel caso specifico, ma in realtà è un caso molto specifico che va ben oltre "configurazioni del server coerenti, esattamente duplicate e procedure di avvio". Sono abbastanza sicuro che non otterresti alcun aumento delle percentuali di collisione se clonassi semplicemente una VM e la eseguissi normalmente. L'auto-seeding di SecureRandom si sforza piuttosto di ottenere qualche vera entropia, al punto da bloccare l'esecuzione se non ne trova: seancassidy.me/wiggle-the-mouse-to-fix-the-test.html
Michael Borgwardt,

114

Wikipedia ha un'ottima risposta http://en.wikipedia.org/wiki/Universally_unique_identifier#Collisions

il numero di UUID casuali della versione 4 che devono essere generati per avere una probabilità del 50% di almeno una collisione è di 2,71 quintilioni, calcolato come segue:

...

Questo numero equivale a generare 1 miliardo di UUID al secondo per circa 85 anni e un file contenente così tanti UUID, a 16 byte per UUID, sarebbe di circa 45 exabyte, molte volte più grande dei più grandi database attualmente esistenti, che sono attivi l'ordine di centinaia di petabyte.

...

Pertanto, affinché ci sia una possibilità su un miliardo di duplicazioni, è necessario generare 103 trilioni di UUID versione 4.


56
Citerei anche da quella pagina, "La probabilità di un duplicato sarebbe di circa il 50% se ogni persona sulla terra possiede 600 milioni di UUID".
Jeff Axelrod,

24
Questo è vero solo per la vera casualità, non per i numeri pseudocasuali come gli UUID java.
Markus,

9
@Markus: completamente sbagliato. La probabilità di collisioni per buoni RNG pseudocasuali, specialmente quelli crittograficamente forti, non è diversa dalla "vera" casualità.
Michael Borgwardt,

6
@Eric - Penso che spetti a te sostenere la tua affermazione. FWIW, gli unici scenari a cui riesco a pensare dove gli UUID di tipo 4 si scontrerebbero più frequentemente di quanto la teoria della probabilità dice che dovrebbero essere: 1) una cattiva fonte di numeri criptati casuali, o 2) una libreria UUID che è stata compromessa.
Stephen C,

13
Questo non risponde alla domanda posta. La domanda riguarda la qualità della casualità in Java UUID.randomUUID(), non le possibilità teoriche per un dato generatore di numeri casuali perfetto.
Kratenko,

69

Qualcuno ha qualche esperienza da condividere?

Esistono 2^122valori possibili per un UUID di tipo 4. (Le specifiche indicano che si perdono 2 bit per il tipo e altri 4 bit per un numero di versione.)

Supponendo che tu dovessi generare 1 milione di UUID casuali al secondo, le probabilità che si verifichi un duplicato nella tua vita sarebbero minime. E per rilevare il duplicato, dovresti risolvere il problema di confrontare 1 milione di nuovi UUID al secondo con tutti gli UUID che hai precedentemente generato 1 !

Le probabilità che qualcuno abbia sperimentato (cioè notato in realtà ) un duplicato nella vita reale sono persino più piccole di quelle sparitamente piccole ... a causa della difficoltà pratica di cercare collisioni.

Ora, naturalmente, in genere utilizzerai un generatore di numeri pseudo-casuale, non una fonte di numeri veramente casuali. Ma penso che possiamo essere sicuri che se stai usando un fornitore di credito per i tuoi numeri casuali di forza crittografica, allora sarà forza crittografica e la probabilità di ripetizioni sarà la stessa di un generatore di numeri casuali ideale (non di parte) .

Tuttavia, se dovessi usare una JVM con un generatore di numeri crittografici "rotti", tutte le scommesse sono disattivate. (E ciò potrebbe includere alcune soluzioni alternative per problemi di "carenza di entropia" su alcuni sistemi. O la possibilità che qualcuno abbia armeggiato con il tuo JRE, sia sul tuo sistema che a monte.)


1 - Supponendo che tu abbia usato "una sorta di btree binario" come proposto da un commentatore anonimo, ogni UUID avrà bisogno di O(NlogN)bit di memoria RAM per rappresentare NUUID distinti assumendo bassa densità e distribuzione casuale dei bit. Ora moltiplicalo per 1.000.000 e il numero di secondi per cui eseguirai l'esperimento. Non penso che sia pratico per il tempo necessario per testare le collisioni di un RNG di alta qualità. Nemmeno con rappresentazioni (ipotetiche) intelligenti.


4
"(E per rilevare il duplicato, dovresti risolvere il problema di confrontare 1 milione di nuovi UUID al secondo con tutti gli UUID che hai precedentemente generato!)" - quella parte è relativamente semplice supponendo che tu abbia archiviato i tuoi uuidi in alcuni tipo di struttura ad albero binario, sarebbe solo una discesa dell'albero per nuovo uuid. Non avresti bisogno di confrontarlo individualmente con tutti gli uuidi generati in precedenza.
user467257,

20

Non sono un esperto, ma presumo che nel corso degli anni abbastanza persone intelligenti abbiano guardato il generatore di numeri casuali di Java. Quindi, suppongo anche che gli UUID casuali siano buoni. Quindi dovresti davvero avere la probabilità teorica di collisione (che è circa 1: 3 × 10 ^ 38 per tutti i possibili UUID. Qualcuno sa come questo cambia solo per gli UUID casuali? È 1/(16*4)di quanto sopra?)

Dalla mia esperienza pratica, non ho mai visto collisioni finora. Probabilmente mi sarò fatto crescere una barba sorprendentemente lunga il giorno in cui avrò il mio primo;)


10
Da Wikipedia: ... In altre parole, solo dopo aver generato 1 miliardo di UUID ogni secondo per i prossimi 100 anni, la probabilità di creare un solo duplicato sarebbe di circa il 50%.
MaVRoSCy,

1
In realtà wikipedia dice che è per i prossimi 85 anni ... dico non contare su di esso, qualcuno da qualche parte ha generato lo stesso UUID come te
smac89

12

In un ex datore di lavoro avevamo una colonna unica che conteneva un uuid casuale. Abbiamo avuto una collisione la prima settimana dopo che è stato schierato. Certo, le probabilità sono basse ma non sono zero. Ecco perché Log4j 2 contiene UuidUtil.getTimeBasedUuid. Genererà un UUID unico per 8.925 anni, purché non si generino più di 10.000 UUID / millisecondi su un singolo server.


2
Sì. Ma la domanda è fare domande sugli UUID casuali (cioè di tipo 4).
Stephen C

1
Si sta chiedendo della probabilità di ottenere una collisione. L'implicazione è che vuole essere sicuro di evitarli.
rgoers

1
(Molto probabilmente la collisione era dovuta a una fonte rotta di casualità per la semina dei PRNG. Pensavo che fosse possibile che fosse dovuto a pura possibilità.)
Stephen C

9

Lo schema di generazione originale per gli UUID era di concatenare la versione UUID con l'indirizzo MAC del computer che sta generando l'UUID e con il numero di intervalli di 100 nanosecondi dall'adozione del calendario gregoriano in Occidente. Rappresentando un singolo punto nello spazio (il computer) e il tempo (il numero di intervalli), la possibilità di una collisione di valori è effettivamente nulla.


1
Questa spiegazione mi rende ottimista nel non vedere le collisioni in pratica. Puoi indicare qualche riferimento per questa affermazione (un codice sorgente sarebbe ancora migliore)?
Dragan Marjanović,

Trovato questo nelle specifiche ietf.org/rfc/rfc4122.txt . Tuttavia sarebbe bello vedere l'attuazione.
Dragan Marjanović,

1
Questo schema non è ciò che Java implementa, tuttavia. Java implementa l'UUID di tipo 4, che è puro casuale e non include l'indirizzo MAC o l'ora. Per inciso, poiché ora ci sono molti dispositivi fisici e virtuali in cui è possibile scegliere il proprio indirizzo MAC, l'algoritmo originale non garantisce l'univocità.
Søren Boisen,

8

Molte delle risposte discutono su quanti UUID dovrebbero essere generati per raggiungere una probabilità del 50% di una collisione. Ma una probabilità di collisione del 50%, 25% o addirittura dell'1% è inutile per un'applicazione in cui la collisione deve essere (praticamente) impossibile.

I programmatori considerano abitualmente come "impossibili" altri eventi che possono e si verificano?

Quando scriviamo i dati su un disco o su una memoria e li rileggiamo di nuovo, diamo per scontato che i dati siano corretti. Facciamo affidamento sulla correzione degli errori del dispositivo per rilevare eventuali danni. Ma la possibilità di errori non rilevati è in realtà intorno ai 2-50 .

Non avrebbe senso applicare uno standard simile agli UUID casuali? Se lo fai, scoprirai che una collisione "impossibile" è possibile in una raccolta di circa 100 miliardi di UUID casuali (2 36,5 ).

Questo è un numero astronomico, ma applicazioni come la fatturazione dettagliata in un sistema sanitario nazionale o la registrazione dei dati dei sensori ad alta frequenza su una vasta gamma di dispositivi potrebbero sicuramente superare questi limiti. Se stai scrivendo la prossima Guida per autostoppisti alla galassia, non provare ad assegnare gli UUID a ciascun articolo!


Come punto di confronto, la possibilità di vincere un jackpot Powerball è 1 su 300 milioni, ma le vendite da 10 a 20 milioni di biglietti sono tipiche. Il punto è che molte persone definiscono "impossibile" come qualcosa di meno di una possibilità su centinaia di milioni.
Erickson,

4

Poiché la maggior parte delle risposte si è concentrata sulla teoria, penso di poter aggiungere qualcosa alla discussione dando un test pratico che ho fatto. Nel mio database ho circa 4,5 milioni di UUID generati utilizzando Java 8 UUID.randomUUID (). I seguenti sono solo alcuni che ho scoperto:

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

Se fosse davvero casuale, la probabilità di avere questo tipo di UUID simili sarebbe considerevolmente bassa (vedi modifica), poiché stiamo considerando solo 4,5 milioni di voci. Quindi, sebbene questa funzione sia buona, in termini di non avere collisioni, per me non sembra così buona come sarebbe in teoria.

Modifica :

Molte persone sembrano non capire questa risposta, quindi chiarirò il mio punto: so che le somiglianze sono "piccole" e lontane da una piena collisione. Tuttavia, volevo solo confrontare UUID.randomUUID () di Java con un vero generatore di numeri casuali, che è la vera domanda.

In un vero generatore di numeri casuali, la probabilità che si verifichi l'ultimo caso dovrebbe aggirarsi intorno allo 0,007%. Pertanto, penso che la mia conclusione sia valida.

La formula è spiegata in questo articolo della wiki en.wikipedia.org/wiki/Birthday_problem


6
Questo non è vero. Questo tipo di somiglianze sorgerebbe anche con un vero generatore di numeri casuali su uuidi 4.5M. Le somiglianze tra gli UUID che hai dato sono piccole e lontane, oh così lontane da una piena collisione.
user3711864

Concordo pienamente con te sul fatto che le somiglianze sono "piccole" e tutt'altro che una collisione totale. Tuttavia, volevo solo confrontare UUID.randomUUID () di Java con un vero generatore di numeri casuali (questa è la domanda). Con alcuni calcoli possiamo vedere che, in un vero generatore di numeri casuali, la probabilità che si verifichi l'ultimo caso sarebbe circa 1-e ^ (- 4500000 ^ 2 / (2 * 36 ^ 11)) = 0,007% = 1 in un 13k. Dovrei essere molto fortunato :)
André Pinheiro

1
Con 4,5 milioni di oggetti e una probabilità 1 su 13k, una collisione parziale del genere non sarebbe prevista 346 volte?
Ben Lee,

No @BenLee, ho calcolato la probabilità che l'evento si verifichi considerando che abbiamo 4,5 milioni di articoli. Non è un'opportunità 1 in 13k per ogni oggetto. La formula che ho usato si trova in questo articolo della wiki en.wikipedia.org/wiki/Birthday_problem
André Pinheiro,

2
Qual era la tua aspettativa? Simile non è lo stesso, vero?
Koray Tugay,

3

Ho giocato alla lotteria lo scorso anno e non ho mai vinto ... ma sembra che ci siano vincitori alla lotteria ...

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

Tipo 1: non implementato. la collisione è possibile se l'UUID è generato nello stesso momento. impl può essere sincronizzato artificialmente per evitare questo problema.

Tipo 2: non vedere mai un'implementazione.

Tipo 3: hash md5: possibile collisione (128 bit tecnici-2 byte)

Tipo 4: casuale: possibile collisione (come lotteria). si noti che l'impl jdk6 non usa un "vero" random random perché l'algoritmo PRNG non è scelto dallo sviluppatore e si può forzare il sistema a usare un algo PRNG "scadente". Quindi il tuo UUID è prevedibile.

Tipo 5: hash sha1: non implementato: possibile collisione (byte tecnici 160 bit-2)


4
La probabilità di vincere alla lotteria è forse una su 10 o 100 milioni (10 ^ 7 o 10 ^ 8) o qualcosa del genere. La probabilità di una collisione con un numero casuale a 128 bit è 3,4 * 10 ^ 28. Dammi un biglietto della lotteria in qualsiasi momento!
Stephen C,

0

Usiamo l'UUID casuale di Java nella nostra applicazione da più di un anno e molto ampiamente. Ma non ci imbattiamo mai in collisioni.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.