Kapan saya harus menggunakan uuid.uuid1 () vs uuid.uuid4 () dalam python?

207

Saya mengerti perbedaan antara keduanya dari dokumen.

uuid1():
Hasilkan UUID dari ID host, nomor urut, dan waktu saat ini

uuid4():
Hasilkan UUID acak.

Jadi uuid1gunakan info mesin / urutan / waktu untuk menghasilkan UUID. Apa pro dan kontra dari penggunaan masing-masing?

Saya tahu uuid1()dapat memiliki masalah privasi, karena didasarkan pada informasi mesin. Saya ingin tahu apakah ada yang lebih halus ketika memilih satu atau yang lain. Saya hanya menggunakan uuid4()sekarang, karena ini adalah UUID yang sepenuhnya acak. Tapi saya bertanya-tanya apakah saya harus menggunakan uuid1untuk mengurangi risiko tabrakan.

Pada dasarnya, saya mencari tips orang untuk praktik terbaik dalam menggunakan satu vs yang lain. Terima kasih!

rocketmonkeys
sumber
3
Berikut ini adalah pendekatan alternatif untuk UUID. Meskipun kemungkinan tabrakan sangat kecil, UUID tidak menjamin keunikan. Untuk menjamin keunikan Anda mungkin ingin menggunakan kunci majemuk sebagai [<system id>, <local id>]. Setiap sistem yang berpartisipasi dalam berbagi data harus memiliki ID unik sistemnya sendiri baik yang ditetapkan selama pengaturan sistem atau diperoleh dari kumpulan ID yang umum. ID lokal adalah ID unik dalam sistem tertentu. Ini melibatkan lebih banyak kerumitan tetapi menjamin keunikan. Maaf untuk offtopic, hanya berusaha membantu.
o
3
Tidak mengurus "masalah privasi" yang dia sebutkan
Shrey

Jawaban:

253

uuid1()dijamin tidak menghasilkan tabrakan (dengan asumsi Anda tidak membuat terlalu banyak tabrakan secara bersamaan). Saya tidak akan menggunakannya jika penting bahwa tidak ada koneksi antara uuiddan komputer, karena alamat mac terbiasa membuatnya unik di seluruh komputer.

Anda dapat membuat duplikat dengan membuat lebih dari 2 14 uuid1 dalam waktu kurang dari 100ns, tetapi ini bukan masalah bagi kebanyakan kasus penggunaan.

uuid4()menghasilkan, seperti yang Anda katakan, UUID acak. Peluang tabrakan benar-benar, sangat, sangat kecil. Cukup kecil, sehingga Anda tidak perlu khawatir. Masalahnya adalah, bahwa generator nomor acak yang buruk membuatnya lebih cenderung mengalami tabrakan.

Jawaban luar biasa dari Bob Aman ini merangkumnya dengan baik. (Saya sarankan membaca seluruh jawaban.)

Terus terang, dalam ruang aplikasi tunggal tanpa aktor jahat, kepunahan semua kehidupan di bumi akan terjadi jauh sebelum Anda memiliki tabrakan, bahkan pada UUID versi 4, bahkan jika Anda menghasilkan beberapa UUID per detik.

Georg Schölly
sumber
Maaf, saya berkomentar tanpa meneliti sepenuhnya - ada bit yang disediakan untuk menjaga agar uuid versi 4 tidak bertabrakan dengan uuid versi 1. Saya akan menghapus komentar asli saya. Lihat tools.ietf.org/html/rfc4122
Mark Ransom
1
@gs Ya, masuk akal dengan apa yang saya baca. uuid1 lebih "unik", sedangkan uuid4 lebih anonim. Jadi pada dasarnya gunakan uuid1 kecuali Anda punya alasan untuk tidak. @mark tebusan: Jawaban yang luar biasa, tidak muncul ketika saya mencari uuid1 / uuid4. Langsung dari mulut kuda, tampaknya.
rocketmonkeys
6
uuid1belum tentu menghasilkan UUID unik jika Anda menghasilkan beberapa per detik pada simpul yang sama. Contoh: [uuid.uuid1() for i in range(2)]. Kecuali tentu saja sesuatu yang aneh sedang terjadi yang saya lewatkan.
Michael Mior
1
@ Michael: uuid1memiliki nomor urut (elemen ke-4 dalam contoh Anda), jadi kecuali Anda menggunakan semua bit di konter Anda tidak memiliki tabrakan.
Georg Schölly
3
@Michael: Saya sudah mencoba meneliti keadaan ketika tabrakan terjadi dan telah menambahkan informasi yang saya temukan.
Georg Schölly
32

Satu contoh ketika Anda dapat mempertimbangkan uuid1()bukan uuid4()adalah ketika UUIDs diproduksi pada mesin yang terpisah , misalnya ketika beberapa transaksi online yang proses pada beberapa mesin untuk skala tujuan.

Dalam situasi seperti itu, risiko tabrakan karena pilihan yang buruk dalam cara generator nomor pseudo-acak diinisialisasi, misalnya, dan juga jumlah UUID yang berpotensi lebih tinggi menghasilkan memberikan kemungkinan yang lebih besar untuk membuat duplikat ID.

Minat lain dari uuid1(), dalam hal ini adalah bahwa mesin di mana setiap GUID awalnya diproduksi secara implisit dicatat (di bagian "simpul" UUID). Ini dan info waktu, dapat membantu jika hanya dengan debugging.

mjv
sumber
20

Tim saya baru saja mengalami masalah menggunakan UUID1 untuk skrip pemutakhiran basis data tempat kami membuat ~ 120k UUID dalam beberapa menit. Tabrakan UUID menyebabkan pelanggaran batasan kunci primer.

Kami telah memutakhirkan 100-an server tetapi pada contoh Amazon EC2 kami beberapa kali mengalami masalah ini. Saya menduga resolusi clock yang buruk dan beralih ke UUID4 menyelesaikannya untuk kami.

Mattias Lagergren
sumber
5

Satu hal yang perlu diperhatikan saat menggunakan uuid1, jika Anda menggunakan panggilan default (tanpa memberikan clock_seqparameter), Anda memiliki peluang mengalami tabrakan: Anda hanya memiliki 14 bit keacakan (menghasilkan 18 entri dalam 100ns memberi Anda sekitar 1% peluang tabrakan lihat paradoks ulang tahun / serangan). Masalahnya tidak akan pernah terjadi pada kebanyakan kasus penggunaan, tetapi pada mesin virtual dengan resolusi clock yang buruk itu akan menggigit Anda.

Guillaume
sumber
7
@ Guilaume akan sangat berguna untuk melihat contoh praktik yang baik menggunakan clock_seq....
eric
@Guilaume Bagaimana Anda menghitung peluang ini sebesar 1%? 14 bit keacakan berarti tabrakan akan dijamin terjadi jika Anda menghasilkan> = 2 ^ 14 id per 100ns dan ini berarti 1% kemungkinan tabrakan adalah ketika Anda menghasilkan kira-kira 163 id per 100 ns
maks
1
@aks Seperti yang saya katakan, Anda harus melihat paradoks ulang tahun .
Guillaume
3

Mungkin sesuatu yang tidak disebutkan adalah lokalitas.

Alamat MAC atau pemesanan berbasis waktu (UUID1) dapat meningkatkan kinerja basis data, karena lebih sulit untuk menyortir angka lebih dekat daripada yang didistribusikan secara acak (UUID4) (lihat di sini ).

Masalah kedua yang terkait, adalah bahwa menggunakan UUID1 dapat berguna dalam debugging, bahkan jika data asal hilang atau tidak disimpan secara eksplisit (ini jelas bertentangan dengan masalah privasi yang disebutkan oleh OP).

cz
sumber
1

Selain jawaban yang diterima, ada opsi ketiga yang dapat berguna dalam beberapa kasus:

v1 dengan MAC acak ("v1mc")

Anda dapat membuat hibrida antara v1 & v4 dengan sengaja membuat UUID v1 dengan alamat MAC siaran acak (ini diizinkan oleh spesifikasi v1). UUID v1 yang dihasilkan bergantung pada waktu (seperti v1 reguler), tetapi tidak memiliki semua informasi khusus host (seperti v4). Ini juga jauh lebih dekat dengan v4 dalam resistansi tabrakan: v1mc = 60 bit waktu + 61 bit acak = 121 bit unik; v4 = 122 bit acak.

Tempat pertama yang saya temui adalah fungsi uuid_generate_v1mc () dari Postgres . Sejak itu saya menggunakan setara python berikut:

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)

(catatan: Saya memiliki versi yang lebih panjang + lebih cepat yang membuat objek UUID secara langsung; dapat memposting jika ada yang mau)


Dalam hal volume besar panggilan / detik, ini memiliki potensi untuk melenyapkan keacakan sistem. Anda bisa menggunakan randommodul stdlib sebagai gantinya (mungkin juga akan lebih cepat). Tetapi PERINGATAN: itu hanya membutuhkan beberapa ratus UUIDs sebelum seorang penyerang dapat menentukan negara RNG, dan dengan demikian sebagian memprediksi UUID masa depan.

import random
from uuid import uuid1

def uuid1mc_insecure():
    return uuid1(random.getrandbits(48) | 0x010000000000)
Eli Collins
sumber
Sepertinya metode ini "seperti" v4 (host-agnostic), tetapi lebih buruk (lebih sedikit, ketergantungan pada urandom, dll). Apakah ada keuntungan dibandingkan dengan hanya uuid4?
rocketmonkeys
Ini terutama hanya upgrade untuk kasus-kasus di mana v1 berguna untuk kualitas berbasis waktu, namun resistensi tabrakan yang lebih kuat dan privasi host diperlukan. Salah satu contoh adalah sebagai kunci utama untuk basis data - dibandingkan dengan v4, v1 uuids akan memiliki lokalitas yang lebih baik saat menulis ke disk, memiliki jenis alami yang lebih berguna, dll. Tetapi jika Anda memiliki kasus di mana penyerang memprediksi 2 ** 61 bit adalah masalah keamanan (misalnya sebagai uuid a nonce), lalu $ diety ya, gunakan uuid4 sebagai gantinya (saya tahu saya lakukan!). Re: menjadi lebih buruk karena menggunakan urandom, saya tidak yakin apa yang Anda maksud - di bawah python, uuid4 () juga menggunakan urandom.
Eli Collins
Barang bagus, itu masuk akal. Adalah baik untuk melihat tidak hanya apa yang dapat Anda lakukan (kode Anda), tetapi juga mengapa Anda menginginkannya. Re: urandom, maksud saya Anda mengonsumsi 2x keacakan (1 untuk uuid1, satu lagi untuk urandom), jadi bisa menggunakan sistem entropi lebih cepat.
rocketmonkeys
Ini sebenarnya sekitar setengah dari uuid4: uuid1 () menggunakan 14 bit untuk clock_seq, yang membulatkan hingga 2 byte urandom. Pembungkus uuid1mc menggunakan 48 bit, yang harus dipetakan ke 6 byte urandom, untuk total urandom (8) yang dikonsumsi per panggilan. sedangkan uuid4 secara langsung memanggil urandom (16) untuk setiap panggilan.
Eli Collins