Ich weiß, dass randomisierte UUIDs theoretisch eine sehr, sehr, sehr geringe Kollisionswahrscheinlichkeit haben, aber ich frage mich in der Praxis, wie gut Java randomUUID()
ist, wenn es nicht zu Kollisionen kommt. Hat jemand Erfahrungen zu teilen?
Ich weiß, dass randomisierte UUIDs theoretisch eine sehr, sehr, sehr geringe Kollisionswahrscheinlichkeit haben, aber ich frage mich in der Praxis, wie gut Java randomUUID()
ist, wenn es nicht zu Kollisionen kommt. Hat jemand Erfahrungen zu teilen?
Antworten:
UUID verwendet java.security.SecureRandom
, die "kryptografisch stark" sein soll. Während die tatsächliche Implementierung nicht angegeben ist und zwischen JVMs variieren kann (was bedeutet, dass alle konkreten Aussagen nur für eine bestimmte JVM gültig sind), muss die Ausgabe einen statistischen Zufallszahlengeneratortest bestehen.
Es ist immer möglich, dass eine Implementierung subtile Fehler enthält, die all dies ruinieren (siehe OpenSSH-Fehler bei der Schlüsselgenerierung), aber ich glaube, es gibt keinen konkreten Grund, sich über die Zufälligkeit von Java-UUIDs Sorgen zu machen.
Wikipedia hat eine sehr gute Antwort http://en.wikipedia.org/wiki/Universally_unique_identifier#Collisions
Die Anzahl der zufälligen UUIDs der Version 4, die generiert werden müssen, um eine 50% ige Wahrscheinlichkeit für mindestens eine Kollision zu haben, beträgt 2,71 Billionen, berechnet wie folgt:
...
Diese Zahl entspricht einer Generierung von 1 Milliarde UUIDs pro Sekunde für ungefähr 85 Jahre, und eine Datei mit diesen vielen UUIDs mit 16 Bytes pro UUID würde ungefähr 45 Exabyte groß sein, ein Vielfaches größer als die größten derzeit existierenden Datenbanken die Größenordnung von Hunderten von Petabyte.
...
Damit eine Wahrscheinlichkeit von einer Milliarde Duplikaten besteht, müssen 103 Billionen UUIDs der Version 4 generiert werden.
UUID.randomUUID()
nicht die theoretischen Chancen für einen bestimmten perfekten Zufallszahlengenerator.
Hat jemand Erfahrungen zu teilen?
Es gibt 2^122
mögliche Werte für eine UUID vom Typ 4. (Die Spezifikation besagt, dass Sie 2 Bits für den Typ und weitere 4 Bits für eine Versionsnummer verlieren.)
Angenommen, Sie würden 1 Million zufällige UUIDs pro Sekunde generieren, wäre die Wahrscheinlichkeit, dass in Ihrem Leben ein Duplikat auftritt, verschwindend gering. Und um das Duplikat zu erkennen, müssten Sie das Problem lösen, 1 Million neue UUIDs pro Sekunde mit allen UUIDs zu vergleichen, die Sie zuvor generiert haben 1 !
Die Wahrscheinlichkeit, dass jemand im wirklichen Leben ein Duplikat erlebt hat (dh tatsächlich bemerkt hat ), ist noch geringer als verschwindend gering ... aufgrund der praktischen Schwierigkeit, nach Kollisionen zu suchen.
Jetzt verwenden Sie normalerweise einen Pseudozufallszahlengenerator, keine Quelle für wirklich zufällige Zahlen. Aber ich denke , wir können sicher sein , dass , wenn Sie einen anerkennenswerten Anbieter für Ihre Verschlüsselungsstärke Zufallszahl verwendet wird , dann ist es wird kryptographische Stärke sein, und die Wahrscheinlichkeit von Wiederholungen wird das gleiche wie für ein Ideal sein (nicht vorgespannt) Zufallszahlengenerator .
Wenn Sie jedoch eine JVM mit einem "kaputten" Krypto-Zufallszahlengenerator verwenden, sind alle Wetten ungültig. (Und das könnte einige der Problemumgehungen für Probleme mit "Entropiemangel" auf einigen Systemen beinhalten. Oder die Möglichkeit, dass jemand an Ihrer JRE herumgebastelt hat, entweder auf Ihrem System oder vorgelagert.)
1 - Angenommen, Sie haben "eine Art binären Baum" verwendet, wie von einem anonymen Kommentator vorgeschlagen, benötigt jede UUID O(NlogN)
Bits des RAM-Speichers, um N
unterschiedliche UUIDs darzustellen, wobei eine geringe Dichte und zufällige Verteilung der Bits vorausgesetzt wird. Multiplizieren Sie dies nun mit 1.000.000 und der Anzahl der Sekunden, für die Sie das Experiment ausführen möchten. Ich denke nicht, dass dies für die Zeitspanne, die zum Testen auf Kollisionen eines hochwertigen RNG benötigt wird, praktisch ist. Nicht einmal mit (hypothetischen) klugen Darstellungen.
Ich bin kein Experte, aber ich würde annehmen, dass sich im Laufe der Jahre genügend kluge Leute mit Javas Zufallszahlengenerator befasst haben. Daher würde ich auch annehmen, dass zufällige UUIDs gut sind. Sie sollten also wirklich die theoretische Kollisionswahrscheinlichkeit haben (die für alle möglichen UUIDs etwa 1: 3 × 10 ^ 38 beträgt . Weiß jemand, wie sich dies nur für zufällige UUIDs ändert? Ist es 1/(16*4)
die oben genannte?)
Aus meiner praktischen Erfahrung habe ich bisher noch nie Kollisionen gesehen. Ich werde wahrscheinlich an dem Tag, an dem ich meinen ersten bekomme, einen erstaunlich langen Bart bekommen haben;)
Bei einem ehemaligen Arbeitgeber hatten wir eine eindeutige Spalte, die eine zufällige UUID enthielt. Wir haben in der ersten Woche nach dem Einsatz eine Kollision bekommen. Sicher, die Chancen sind gering, aber sie sind nicht Null. Aus diesem Grund enthält Log4j 2 UuidUtil.getTimeBasedUuid. Es wird eine UUID generiert, die 8.925 Jahre lang eindeutig ist, solange Sie nicht mehr als 10.000 UUIDs / Millisekunde auf einem einzelnen Server generieren.
Das ursprüngliche Generierungsschema für UUIDs bestand darin, die UUID-Version mit der MAC-Adresse des Computers zu verketten, der die UUID generiert, und mit der Anzahl der Intervalle von 100 Nanosekunden seit der Einführung des Gregorianischen Kalenders im Westen. Durch die Darstellung eines einzelnen Punktes im Raum (Computer) und der Zeit (Anzahl der Intervalle) ist die Wahrscheinlichkeit einer Kollision der Werte praktisch gleich Null.
In vielen Antworten wird erläutert, wie viele UUIDs generiert werden müssten, um eine 50% ige Kollisionswahrscheinlichkeit zu erreichen. Eine Kollisionswahrscheinlichkeit von 50%, 25% oder sogar 1% ist jedoch für eine Anwendung wertlos, bei der eine Kollision (praktisch) unmöglich sein muss.
Werden andere Ereignisse, die auftreten können und tatsächlich auftreten, von Programmierern routinemäßig als "unmöglich" abgetan?
Wenn wir Daten auf eine Festplatte oder einen Speicher schreiben und wieder zurücklesen, gehen wir davon aus, dass die Daten korrekt sind. Wir verlassen uns auf die Fehlerkorrektur des Geräts, um Beschädigungen zu erkennen. Die Wahrscheinlichkeit von unentdeckten Fehlern liegt jedoch tatsächlich bei 2 bis 50 .
Wäre es nicht sinnvoll, einen ähnlichen Standard auf zufällige UUIDs anzuwenden? Wenn Sie dies tun, werden Sie feststellen, dass eine "unmögliche" Kollision in einer Sammlung von rund 100 Milliarden zufälligen UUIDs möglich ist (2 36,5 ).
Dies ist eine astronomische Zahl, aber Anwendungen wie die Einzelabrechnung in einem nationalen Gesundheitssystem oder die Protokollierung von Hochfrequenzsensordaten auf einer großen Anzahl von Geräten könnten definitiv an diese Grenzen stoßen. Wenn Sie den nächsten Per Anhalter durch die Galaxis schreiben , versuchen Sie nicht, jedem Artikel UUIDs zuzuweisen!
Da sich die meisten Antworten auf die Theorie konzentrierten, denke ich, dass ich der Diskussion etwas hinzufügen kann, indem ich einen praktischen Test gebe, den ich gemacht habe. In meiner Datenbank habe ich ungefähr 4,5 Millionen UUIDs, die mit Java 8 UUID.randomUUID () generiert wurden. Die folgenden sind nur einige, die ich herausgefunden habe:
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
Wenn es wirklich zufällig wäre, wäre die Wahrscheinlichkeit, solche ähnlichen UUIDs zu haben, erheblich gering (siehe Bearbeiten), da wir nur 4,5 Millionen Einträge berücksichtigen. Also, auch wenn diese Funktion gut ist, in Bezug auf die nicht mit Kollisionen, für mich scheint es nicht , dass gut , wie es in der Theorie wäre.
Bearbeiten :
Viele Leute scheinen diese Antwort nicht zu verstehen, deshalb werde ich meinen Standpunkt klarstellen: Ich weiß, dass die Ähnlichkeiten "klein" und weit von einer vollständigen Kollision entfernt sind. Ich wollte jedoch nur die UUID.randomUUID () von Java mit einem echten Zufallszahlengenerator vergleichen, was die eigentliche Frage ist.
In einem echten Zufallszahlengenerator würde die Wahrscheinlichkeit, dass der letzte Fall eintritt, bei = 0,007% liegen. Daher denke ich, dass meine Schlussfolgerung steht.
Die Formel wird in diesem Wiki-Artikel en.wikipedia.org/wiki/Birthday_problem erklärt
Ich spiele letztes Jahr bei einer Lotterie und habe noch nie gewonnen ... aber es scheint, dass die Lotterie Gewinner hat ...
doc: http://tools.ietf.org/html/rfc4122
Typ 1: nicht implementiert. Kollisionen sind möglich, wenn die UUID im selben Moment generiert wird. impl kann künstlich a-synchronisiert werden, um dieses Problem zu umgehen.
Typ 2: Sehen Sie niemals eine Implementierung.
Typ 3: md5 Hash: Kollision möglich (128 Bit-2 technische Bytes)
Typ 4: zufällig: Kollision möglich (als Lotterie). Beachten Sie, dass das jdk6-Gerät keinen "wahren" sicheren Zufall verwendet, da der PRNG-Algorithmus nicht vom Entwickler ausgewählt wird und Sie das System zwingen können, ein "schlechtes" PRNG-Algo zu verwenden. Ihre UUID ist also vorhersehbar.
Typ 5: sha1 Hash: nicht implementiert: Kollision möglich (160 Bit-2 technische Bytes)