Je sais que les UUID randomisés ont une probabilité de collision très, très, très faible en théorie, mais je me demande, en pratique, à quel point Java randomUUID()
est bon en termes de non-collision? Quelqu'un at-il une expérience à partager?
Je sais que les UUID randomisés ont une probabilité de collision très, très, très faible en théorie, mais je me demande, en pratique, à quel point Java randomUUID()
est bon en termes de non-collision? Quelqu'un at-il une expérience à partager?
Réponses:
UUID utilise java.security.SecureRandom
, qui est censé être "cryptographiquement fort". Bien que l'implémentation réelle ne soit pas spécifiée et puisse varier entre les JVM (ce qui signifie que toutes les déclarations concrètes faites ne sont valables que pour une JVM spécifique), elle oblige la sortie à passer un test de générateur de nombres aléatoires statistiques.
Il est toujours possible qu'une implémentation contienne des bogues subtils qui ruinent tout cela (voir le bogue de génération de clé OpenSSH) mais je ne pense pas qu'il y ait de raison concrète de s'inquiéter du caractère aléatoire des UUID Java.
Wikipedia a une très bonne réponse http://en.wikipedia.org/wiki/Universally_unique_identifier#Collisions
le nombre d'UUID aléatoires de la version 4 qui doivent être générés pour avoir une probabilité de 50% d'au moins une collision est de 2,71 quintillions, calculé comme suit:
...
Ce nombre équivaut à générer 1 milliard d'UUID par seconde pendant environ 85 ans, et un fichier contenant ce nombre d'UUID, à 16 octets par UUID, serait d'environ 45 exaoctets, plusieurs fois plus grand que les plus grandes bases de données actuellement en existence, qui sont sur l'ordre de centaines de pétaoctets.
...
Ainsi, pour qu'il y ait une chance sur un milliard de duplication, 103 000 milliards d'UUID version 4 doivent être générés.
UUID.randomUUID()
, et non sur les chances théoriques pour un générateur de nombres aléatoires parfait donné.
Quelqu'un at-il une expérience à partager?
Il existe 2^122
des valeurs possibles pour un UUID de type 4. (La spécification indique que vous perdez 2 bits pour le type et 4 bits supplémentaires pour un numéro de version.)
En supposant que vous deviez générer 1 million d'UUID aléatoires par seconde, les chances qu'un doublon se produise au cours de votre vie seraient extrêmement faibles. Et pour détecter le doublon, vous devez résoudre le problème de la comparaison de 1 million de nouveaux UUID par seconde avec tous les UUID que vous avez précédemment générés 1 !
Les chances que quiconque ait connu (c'est-à-dire réellement remarqué ) un doublon dans la vie réelle soient encore plus petites que minuscules ... en raison de la difficulté pratique de rechercher des collisions.
Maintenant, bien sûr, vous utiliserez généralement un générateur de nombres pseudo-aléatoires, pas une source de nombres vraiment aléatoires. Mais je pense que nous pouvons être convaincus que si vous utilisez un fournisseur crédible pour vos nombres aléatoires de force cryptographique, alors ce sera la force cryptographique, et la probabilité de répétitions sera la même que pour un générateur de nombres aléatoires idéal (non biaisé) .
Cependant, si vous deviez utiliser une machine virtuelle Java avec un générateur de nombres aléatoires cryptés "cassé", tous les paris sont désactivés. (Et cela pourrait inclure certaines des solutions de contournement pour les problèmes de «pénurie d'entropie» sur certains systèmes. Ou la possibilité que quelqu'un ait bricolé avec votre JRE, soit sur votre système, soit en amont.)
1 - En supposant que vous avez utilisé "une sorte de btree binaire" comme proposé par un commentateur anonyme, chaque UUID va avoir besoin de O(NlogN)
bits de mémoire RAM pour représenter N
des UUID distincts en supposant une faible densité et une distribution aléatoire des bits. Multipliez maintenant cela par 1 000 000 et le nombre de secondes pendant lesquelles vous allez exécuter l'expérience. Je ne pense pas que ce soit pratique pour la durée nécessaire pour tester les collisions d'un RNG de haute qualité. Pas même avec des représentations intelligentes (hypothétiques).
Je ne suis pas un expert, mais je suppose que suffisamment de gens intelligents ont regardé le générateur de nombres aléatoires de Java au fil des ans. Par conséquent, je suppose également que les UUID aléatoires sont bons. Donc, vous devriez vraiment avoir la probabilité de collision théorique (qui est d'environ 1: 3 × 10 ^ 38 pour tous les UUID possibles. Quelqu'un sait-il comment cela change pour les UUID aléatoires uniquement? Est-ce 1/(16*4)
de ce qui précède?)
D'après mon expérience pratique, je n'ai jamais vu de collision jusqu'à présent. J'aurai probablement une barbe étonnamment longue le jour où j'aurai ma première;)
Chez un ancien employeur, nous avions une colonne unique qui contenait un uuid aléatoire. Nous avons eu une collision la première semaine après son déploiement. Bien sûr, les chances sont faibles mais elles ne sont pas nulles. C'est pourquoi Log4j 2 contient UuidUtil.getTimeBasedUuid. Il générera un UUID unique pendant 8 925 ans tant que vous ne générerez pas plus de 10 000 UUID / milliseconde sur un seul serveur.
Le schéma de génération original pour les UUID consistait à concaténer la version de l'UUID avec l'adresse MAC de l'ordinateur qui génère l'UUID et avec le nombre d'intervalles de 100 nanosecondes depuis l'adoption du calendrier grégorien en Occident. En représentant un seul point dans l'espace (l'ordinateur) et le temps (le nombre d'intervalles), le risque de collision de valeurs est effectivement nul.
De nombreuses réponses discutent du nombre d'UUID qui devraient être générés pour atteindre 50% de chances de collision. Mais un risque de collision de 50%, 25% ou même 1% ne vaut rien pour une application où la collision doit être (pratiquement) impossible.
Les programmeurs rejettent-ils régulièrement comme «impossibles» les autres événements qui peuvent et se produisent?
Lorsque nous écrivons des données sur un disque ou une mémoire et les relisons, nous tenons pour acquis que les données sont correctes. Nous comptons sur la correction d'erreur de l'appareil pour détecter toute corruption. Mais le risque d'erreurs non détectées se situe en réalité autour de 2 à 50 .
Ne serait-il pas logique d'appliquer une norme similaire à des UUID aléatoires? Si vous le faites, vous constaterez qu'une collision "impossible" est possible dans une collection d'environ 100 milliards d'UUID aléatoires (2 36,5 ).
Il s'agit d'un nombre astronomique, mais des applications telles que la facturation détaillée dans un système de santé national ou l'enregistrement de données de capteurs haute fréquence sur un large éventail d'appareils pourraient définitivement se heurter à ces limites. Si vous écrivez le prochain guide de l'auto-stoppeur sur la galaxie, n'essayez pas d'attribuer des UUID à chaque article!
Comme la plupart des réponses se sont concentrées sur la théorie, je pense que je peux ajouter quelque chose à la discussion en donnant un test pratique que j'ai fait. Dans ma base de données, j'ai environ 4,5 millions d'UUID générés à l'aide de Java 8 UUID.randomUUID (). Les suivants sont quelques-uns que j'ai découvert:
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
S'il était vraiment aléatoire, la probabilité d'avoir ce type d'UUID similaires serait considérablement faible (voir modifier), car nous ne considérons que 4,5 millions d'entrées. Donc, bien que cette fonction soit bonne, en termes de non collision, pour moi elle ne semble pas aussi bonne qu'elle le serait en théorie.
Modifier :
Beaucoup de gens semblent ne pas comprendre cette réponse, je vais donc clarifier mon point: je sais que les similitudes sont "petites" et loin d'une collision complète. Cependant, je voulais juste comparer l'UUID.randomUUID () de Java avec un véritable générateur de nombres aléatoires, ce qui est la vraie question.
Dans un véritable générateur de nombres aléatoires, la probabilité que le dernier cas se produise serait d'environ = 0,007%. Par conséquent, je pense que ma conclusion est valable.
La formule est expliquée dans cet article wiki en.wikipedia.org/wiki/Birthday_problem
Je joue à la loterie l'année dernière, et je n'ai jamais gagné ... mais il semble que la loterie ait des gagnants ...
doc: http://tools.ietf.org/html/rfc4122
Type 1: non implémenté. la collision est possible si l'uuid est généré au même moment. impl peut être synchronisé artificiellement afin de contourner ce problème.
Type 2: ne voyez jamais d'implémentation.
Type 3: hachage md5: collision possible (128 bits-2 octets techniques)
Type 4: aléatoire: collision possible (comme loterie). notez que l'impl jdk6 n'utilise pas un "vrai" aléatoire sécurisé car l'algorithme PRNG n'est pas choisi par le développeur et vous pouvez forcer le système à utiliser un algo PRNG "pauvre". Votre UUID est donc prévisible.
Type 5: hachage sha1: non implémenté: collision possible (160 octets techniques 2 bits)