web-dev-qa-db-fra.com

Quand devrais-je utiliser uuid.uuid1 () contre uuid.uuid4 () en python?

Je comprends les différences entre les deux docs.

uuid1():
Générer un UUID à partir d'un ID d'hôte, d'un numéro de séquence et de l'heure actuelle

uuid4():
Génère un UUID aléatoire.

Donc uuid1 Utilise les informations machine/séquence/heure pour générer un UUID. Quels sont les avantages et les inconvénients de l'utilisation de chacun?

Je sais que uuid1() peut avoir des problèmes de confidentialité, car il est basé sur des informations machine. Je me demande s'il n'y a pas plus subtile dans le choix de l'un ou de l'autre. Je viens d'utiliser uuid4() maintenant, car c'est un UUID complètement aléatoire. Mais je me demande si je devrais utiliser uuid1 Pour réduire le risque de collision.

En gros, je recherche les astuces des gens concernant les meilleures pratiques pour utiliser l’un par rapport à l’autre. Merci!

193
rocketmonkeys

Il est garanti que uuid1() ne produira aucune collision (en supposant que vous n'en créez pas trop en même temps). Je ne l'utiliserais pas s'il était important qu'il n'y ait pas de connexion entre le uuid et l'ordinateur, l'adresse mac étant utilisée pour la rendre unique sur tous les ordinateurs.

Vous pouvez créer des doublons en créant plus de 214 uuid1 en moins de 100ns, mais ce n'est pas un problème pour la plupart des cas d'utilisation.

uuid4() génère, comme vous l'avez dit, un UUID aléatoire. Le risque de collision est vraiment, vraiment, vraiment petit. Assez petit pour ne pas t'inquiéter. Le problème est qu’un mauvais générateur de nombres aléatoires augmente les risques de collision.

Cette excellente réponse de Bob Aman le résume bien. (Je recommande de lire toute la réponse.)

Franchement, dans un seul espace d'application sans acteurs malveillants, l'extinction de toute vie sur Terre se produira bien avant la collision, même avec un UUID version 4, même si vous générez pas mal d'UUID par seconde.

240
Georg Schölly

Vous pouvez par exemple considérer que uuid1() plutôt que uuid4() est lorsque les UUID sont générés sur des machines distinctes, par exemple lorsque plusieurs transactions en ligne sont traitées sur plusieurs machines. mise à l'échelle des fins.

Dans une telle situation, les risques de collision dus à de mauvais choix dans la manière d'initialiser les générateurs de nombres pseudo-aléatoires, par exemple, et les nombres potentiellement plus élevés d'UUID produits rendent plus probable la possibilité de créer des ID en double.

Un autre intérêt de uuid1(), dans ce cas, est que la machine où chaque GUID a été initialement produit est implicitement enregistrée (dans la partie "noeud" de l'UUID). Ceci et les informations temporelles peuvent aider, ne serait-ce que pour le débogage.

31
mjv

Mon équipe vient tout juste de rencontrer des problèmes pour utiliser UUID1 pour un script de mise à niveau de base de données dans lequel nous avons généré environ 120 000 UUID en quelques minutes. La collision d'UUID a entraîné la violation d'une contrainte de clé primaire.

Nous avons mis à niveau des centaines de serveurs, mais nous avons rencontré ce problème à quelques reprises sur nos instances Amazon EC2. Je soupçonne que la résolution d'horloge médiocre et le passage à UUID4 l'ont résolu pour nous.

15
Mattias Lagergren

Une chose à noter lorsque vous utilisez uuid1, si vous utilisez l’appel par défaut (sans donner clock_seq paramètre), vous avez une chance de vous heurter à des collisions: vous n’avez que 14 bits d’aléatoire (générer 18 entrées dans un rayon de 100ns vous donne environ 1% de chances d’une collision (voir paradoxe anniversaire/attaque). Le problème ne se produira jamais dans la plupart des cas d'utilisation, mais sur une machine virtuelle avec une résolution d'horloge faible, il vous mordra.

5
Guillaume

Peut-être que quelque chose qui n'a pas été mentionné est celui de la localité.

Une adresse MAC ou un ordre basé sur le temps (UUID1) peut améliorer les performances de la base de données, car il est moins fastidieux de trier les nombres plus rapprochés que ceux distribués de manière aléatoire (UUID4) (voir ici ).

Un autre problème connexe est que l’utilisation de l’UUID1 peut être utile lors du débogage, même si les données Origin sont perdues ou ne sont pas explicitement stockées (ceci est évidemment en conflit avec le problème de confidentialité mentionné par le PO).

3
c z

Outre la réponse acceptée, il existe une troisième option qui peut être utile dans certains cas:

v1 avec MAC aléatoire ("v1mc")

Vous pouvez créer un hybride entre v1 et v4 en générant délibérément des UUID v1 avec une adresse MAC de diffusion aléatoire (ceci est autorisé par la spécification v1). L'UUID v1 résultant dépend du temps (comme v1 normal), mais il manque toutes les informations spécifiques à l'hôte (comme v4). La résistance aux collisions est également beaucoup plus proche de v4: v1mc = 60 bits de temps + 61 bits aléatoires = 121 bits uniques; v4 = 122 bits aléatoires.

Le premier endroit où j'ai rencontré cela était la fonction id_generate_v1mc () de Postgres. Depuis, j'ai utilisé l'équivalent python suivant:

from os import urandom
from uuid import uuid1
_int_from_bytes = int.from_bytes  # py3 only

def uuid1mc():
    # NOTE: The constant here is required by the UUIDv1 spec...
    return uuid1(_int_from_bytes(urandom(6), "big") | 0x010000000000)

(note: j'ai une version plus longue et plus rapide qui crée directement l'objet UUID; je peux poster si quelqu'un le souhaite)


En cas de grands volumes d'appels/seconde, cela peut potentiellement épuiser le caractère aléatoire du système. Vous pourriez utiliser le module stdlib random à la place (ce sera probablement aussi plus rapide). Mais soyez averti: il suffit de quelques centaines d’UUID pour qu’un attaquant puisse déterminer l’état du RNG, et donc prédire partiellement les futurs UUID.

import random
from uuid import uuid1

def uuid1mc_insecure():
    return uuid1(random.getrandbits(48) | 0x010000000000)
1
Eli Collins