¿Cuándo debería usar uuid.uuid1() vs. uuid.uuid4() en python?
short uuid python (6)
Entiendo las diferencias entre los dos de los docs.
uuid1()
:
Genere un UUID a partir de una ID de host, un número de secuencia y la hora actual
uuid4()
:
Genera un UUID aleatorio.
Entonces uuid1
usa información de máquina / secuencia / tiempo para generar un UUID. ¿Cuáles son los pros y los contras de usar cada uno?
Sé que uuid1()
puede tener problemas de privacidad, ya que está basado en la información de la máquina. Me pregunto si hay algo más sutil al elegir uno u otro. Solo uso uuid4()
este momento, ya que es un UUID completamente aleatorio. Pero me pregunto si debería usar uuid1
para disminuir el riesgo de colisiones.
Básicamente, estoy buscando los consejos de las personas sobre las mejores prácticas sobre el uso de uno frente al otro. ¡Gracias!
Además de la respuesta aceptada, hay una tercera opción que puede ser útil en algunos casos:
v1 con MAC aleatorio ("v1mc")
Puede crear un híbrido entre v1 y v4 generando deliberadamente v1 UUID con una dirección MAC de difusión aleatoria (esto está permitido por la especificación v1). El UUID v1 resultante depende del tiempo (como v1 regular), pero carece de toda la información específica del host (como v4). También está mucho más cerca de v4 en su resistencia a la colisión: v1mc = 60 bits de tiempo + 61 bits aleatorios = 121 bits únicos; v4 = 122 bits aleatorios.
El primer lugar que encontré fue la función uuid_generate_v1mc() Postgres. Desde entonces he usado el siguiente equivalente de Python:
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)
(nota: tengo una versión más larga + más rápida que crea el objeto UUID directamente; puede publicar si alguien quiere)
En el caso de grandes volúmenes de llamadas / segundo, esto tiene el potencial de agotar la aleatoriedad del sistema. Podría usar el módulo random
stdlib en su lugar (probablemente también sea más rápido). Pero SEA ADVERTIDO: solo se necesitan unos pocos cientos de UUID antes de que un atacante pueda determinar el estado de RNG, y así predecir parcialmente los UUID futuros.
import random
from uuid import uuid1
def uuid1mc_insecure():
return uuid1(random.getrandbits(48) | 0x010000000000)
Mi equipo simplemente tuvo problemas al usar UUID1 para una secuencia de comandos de actualización de base de datos donde generamos ~ 120k UUID en un par de minutos. La colisión UUID provocó la violación de una restricción de clave primaria.
Hemos actualizado cientos de servidores, pero en nuestras instancias de Amazon EC2 nos topamos con este problema varias veces. Sospecho que la mala resolución del reloj y el cambio a UUID4 lo resolvieron para nosotros.
Quizás algo que no se ha mencionado es el de la localidad.
Una dirección MAC o una ordenación basada en el tiempo (UUID1) puede permitir un mayor rendimiento de la base de datos, ya que es menos útil ordenar los números más cerca que los distribuidos al azar (UUID4) (ver here ).
Un segundo problema relacionado es que el uso de UUID1 puede ser útil en la depuración, incluso si los datos de origen se pierden o no se almacenan explícitamente (esto obviamente está en conflicto con el problema de privacidad mencionado por el OP).
Una cosa a tener en cuenta al usar uuid1
, si usas la llamada predeterminada (sin dar el parámetro clock_seq
) tienes la posibilidad de clock_seq
con colisiones: solo tienes 14 bits de aleatoriedad (generar 18 entradas dentro de 100ns te da aproximadamente 1% de probabilidad de un colisión ver paradoja / ataque de cumpleaños). El problema nunca ocurrirá en la mayoría de los casos de uso, pero en una máquina virtual con mala resolución de reloj te morderá.
Una instancia en la que puede considerar uuid1()
lugar de uuid4()
es cuando los UUID se producen en máquinas separadas , por ejemplo, cuando se procesan varias transacciones en línea en varias máquinas para escalar.
En tal situación, los riesgos de tener colisiones debido a malas elecciones en la forma en que se inicializan los generadores de números pseudoaleatorios, por ejemplo, y también los números potencialmente más altos de UUID producidos hacen más probable la posibilidad de crear ID duplicados.
Otro interés de uuid1()
, en ese caso es que la máquina donde se produjo inicialmente cada GUID se registra implícitamente (en la parte "nodo" del UUID). Esta y la información de tiempo, pueden ayudar si solo con la depuración.
uuid1()
garantiza que no producirá ninguna colisión (suponiendo que no crea demasiados al mismo tiempo). No lo usaría si es importante que no haya conexión entre el uuid
y la computadora, ya que la dirección MAC se usa para hacerlo único en todas las computadoras.
Puede crear duplicados creando más de 2 14 uuid1 en menos de 100ns, pero esto no es un problema para la mayoría de los casos de uso.
uuid4()
genera, como dijiste, un UUID aleatorio. La posibilidad de una colisión es realmente muy pequeña. Lo suficientemente pequeño, que no debes preocuparte por eso. El problema es que un generador de números aleatorios malo hace que sea más probable que haya colisiones.
Esta excelente respuesta de Bob Aman lo resume muy bien. (Recomiendo leer toda la respuesta).
Francamente, en un solo espacio de aplicación sin actores maliciosos, la extinción de toda la vida en la Tierra ocurrirá mucho antes de que tengas una colisión, incluso en un UUID de la versión 4, incluso si estás generando bastantes UUID por segundo.