96 votes

Collisions lors de la génération d'UUIDs en JavaScript

Il s'agit de cette question . J'utilise le code ci-dessous à partir de cette réponse pour générer un UUID en JavaScript :

'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
    var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
    return v.toString(16);
});

Cette solution semblait fonctionner correctement, mais j'obtiens des collisions. Voici ce que j'ai :

  • Une application web fonctionnant dans Google Chrome.
  • 16 utilisateurs.
  • environ 4000 UUIDs ont été générés au cours des deux derniers mois par ces utilisateurs.
  • J'ai obtenu environ 20 collisions - par exemple, un nouvel UUID généré aujourd'hui était le même qu'il y a environ deux mois (utilisateur différent).

Quelle est la cause de ce problème et comment puis-je l'éviter ?

2 votes

Combine un bon nombre aléatoire avec le temps actuel (en millisecondes). Les chances que le nombre aléatoire entre en collision exactement au même moment sont vraiment, vraiment, vraiment faibles.

7 votes

@jfriend00 si vous devez faire cela alors ce n'est pas un "bon nombre aléatoire", pas même un nombre pseudo-aléatoire décent.

2 votes

Que fait le (r&0x3|0x8) partie signifie / évaluation à ?

36voto

Veselin Kulov Points 241

Il y a effectivement des collisions, mais seulement sous Google Chrome. Consultez mon expérience sur le sujet dans Problème de générateur de nombres aléatoires dans Google Chrome

Il semble que les collisions ne se produisent que lors des premiers appels de Math.random. En effet, si vous exécutez simplement la méthode createGUID / testGUIDs ci-dessus (qui est évidemment la première chose que j'ai essayée), cela fonctionne sans aucune collision.

Ainsi, pour effectuer un test complet, il faut redémarrer Google Chrome, générer 32 octets, redémarrer Chrome, générer, redémarrer, générer, etc.

2 votes

C'est assez inquiétant. Quelqu'un a-t-il signalé un bug ?

1 votes

J'aime particulièrement le lien vers de meilleurs générateurs de nombres aléatoires en javascript : baagoe.com/fr/RandomMusings/javascript

0 votes

Malheureusement, ce lien est maintenant rompu :(

36voto

broofa Points 21663

Mon avis est que Math.random() est cassé sur votre système pour une raison quelconque (aussi bizarre que cela puisse paraître). C'est le premier rapport que j'ai vu de quelqu'un obtenant des collisions.

node-uuid a un harnais de test que vous pouvez utiliser pour tester la distribution des chiffres hexadécimaux dans ce code. Si cela semble correct, alors ce n'est pas Math.random() alors essayez de substituer l'implémentation de l'UUID que vous utilisez dans le fichier uuid() et voyez si vous obtenez toujours de bons résultats.

[Mise à jour : vient de voir Rapport de Veselin à propos du bug avec Math.random() au démarrage. Puisque le problème ne se pose qu'au démarrage, la node-uuid est peu susceptible d'être utile. Je commenterai plus en détail le lien avec devoluk.com].

1 votes

Merci, je vais utiliser uuid.js maintenant, puisqu'il utilise la cryptographie forte du navigateur si elle est disponible. Je vais voir s'il y a des collisions.

0 votes

Pouvez-vous fournir un lien vers le code uuid.js auquel vous faites référence ? (désolé, je ne suis pas sûr de la librairie dont vous parlez).

10 votes

Je n'ai eu aucune collision jusqu'à présent :)

21voto

Ken Smith Points 9165

Pour que d'autres personnes soient au courant, je rencontrais un nombre étonnamment élevé de collisions apparentes en utilisant la technique de génération d'UUID mentionnée ici. Ces collisions ont continué même après que je sois passé à seedrandom pour mon générateur de nombres aléatoires. J'ai dû m'arracher les cheveux, comme vous pouvez l'imaginer.

J'ai fini par comprendre que le problème était (presque ?) exclusivement lié aux robots d'exploration de Google. Dès que j'ai commencé à ignorer les requêtes avec "googlebot" dans le champ user-agent, les collisions ont disparu. Je suppose qu'ils doivent mettre en cache les résultats des scripts JS d'une manière semi-intelligente, ce qui a pour conséquence que leur navigateur d'araignée ne peut pas être considéré comme se comportant de la même manière que les navigateurs normaux.

Juste un FYI.

2 votes

Nous avons rencontré le même problème avec notre système de métrique. Nous avons vu des milliers de collisions d'UUID en utilisant le module 'node-uuid' pour générer des ID de session dans le navigateur. Il s'avère que c'était googlebot depuis le début. Merci !

4voto

user533676 Points 170

Je viens d'effectuer un test rudimentaire de 100 000 itérations dans Chrome en utilisant l'algorithme UUID que vous avez publié, et je n'ai obtenu aucune collision. Voici un extrait de code :

var createGUID = function() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
        var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
        return v.toString(16);
    });
}

var testGUIDs = function(upperlimit) {
    alert('Doing collision test on ' + upperlimit + ' GUID creations.');
    var i=0, guids=[];
    while (i++<upperlimit) {
        var guid=createGUID();
        if (guids.indexOf(guid)!=-1) {
            alert('Collision with ' + guid + ' after ' + i + ' iterations');
        }
        guids.push(guid);
    }
    alert(guids.length + ' iterations completed.');
}

testGUIDs(100000);

4 votes

Oui, j'ai aussi effectué quelques tests locaux et je n'ai pas eu de collisions. Les collisions se produisent entre les UUIDs qui sont générés sur les machines de différents utilisateurs. Je devrais peut-être générer des données sur différentes machines et vérifier les collisions.

2 votes

De plus, j'ai remarqué que les collisions se produisent entre des UUIDs générés à 3-4 semaines d'intervalle.

0 votes

Très bizarre. Sur quelle plateforme fonctionnez-vous ?

-2voto

Rishi Points 219

Moi aussi, j'avais du mal à générer des identificateurs uniques globaux garantis qui ne soient pas sujets à des collisions. J'ai fini par écrire un plugin javascript qui garantit soi-disant l'unicité.

N'hésitez pas à l'essayer : https://github.com/mongoh/tuid

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X