Java UUID.randomUUID ne kadar iyi?


311

Randomize UUID'lerin teoride çarpışma olasılığı çok, çok, çok düşük olduğunu biliyorum , ama pratikte Java'nın randomUUID()çarpışma olmaması açısından ne kadar iyi olduğunu merak ediyorum ? Paylaşacak herhangi bir tecrübesi olan var mı?


10
Deneyimlerime göre, hiç bir çarpışma görmedim ;-)
Thilo

4
Algoritmalar RFC1422'de belirtilmiştir: ietf.org/rfc/rfc4122.txt
skaffman

8
@skaffman: RFC rastgele rakamlar oluşturmak için kullanılan algoritma hakkında kesinlikle hiçbir şey söylemiyor.
Michael Borgwardt

4
Bu daha açık uçlu bir soru olduğundan, sanırım herhangi bir cevabı doğru cevap olarak işaretlemeyeceğim; bunun yerine, iyi olduğunu düşündüğüm cevapların her birine bir oy vereceğim :)
Alvin

5
Vikipedi'den: Başka bir deyişle, sadece önümüzdeki 100 yıl için saniyede 1 milyar UUID oluşturduktan sonra, sadece bir kopya oluşturma olasılığı yaklaşık% 50 olacaktır.
MaVRoSCy

Yanıtlar:


168

java.security.SecureRandom"Kriptografik olarak güçlü" olması gereken UUID kullanır . Gerçek uygulama belirtilmemiş ve JVM'ler arasında değişiklik gösterebilse de (yapılan somut ifadelerin yalnızca belirli bir JVM için geçerli olduğu anlamına gelir), çıktının istatistiksel rasgele sayı üreteci testini geçmesi zorunludur.

Bir uygulamanın her şeyi mahveden ince hatalar içermesi her zaman mümkündür (bkz. OpenSSH anahtar oluşturma hatası), ancak Java UUID'lerin rastgeleliği hakkında endişelenmenin somut bir nedeni olduğunu düşünmüyorum.


34
"Bir uygulamanın ince böcekler içermesi her zaman mümkündür ..." - Ya da (teneke folyo şapka giyerek) ... kasıtlı ince kusurlar. <:-)
Stephen C

25
Kriptografik güç, çarpışma sorunu için tamamen önemsizdir.
osa

14
@osa: Çarpışma üretmemek (mükemmel rastgelelikten beklenenden fazla) bir RNG için en düşük kalite gereksinimi iken, kriptografik güç en yüksektir. Başka bir deyişle, kriptografik olarak güçlü bir RNG kesinlikle beklenenden daha fazla çarpışma üretmeyecektir.
Michael Borgwardt

3
Bununla birlikte, blogs.vmware.com/cto/… içinde UUID'leri çalkalayan bir JVM çalıştırırsanız , muhtemelen çok sayıda çarpışma yaşayacağınızı belirtmek yararlı olabilir . Tüm yazılım RNG'leri PRNG'lerdir ve sonuçta sadece entropi kaynakları kadar iyidirler; aynı şekilde tohumlanan iki PRNG de aynı şekilde davranır ve bu tutarlı, kesin olarak yinelenen sunucu kurulumları ve başlatma prosedürleri ile şaşırtıcı bir şekilde ortaya çıkabilir.
user508633 25:15

@ user508633: Aslında bu özel durumda% 100'lük bir çarpışma oranı elde etmeyi beklerdim, ama gerçekten de "tutarlı, tam yinelenen sunucu kurulumları ve başlatma prosedürlerinin" çok ötesinde bir durum. Sadece bir sanal makineyi klonlayıp normal şekilde çalıştırırsanız, artan çarpışma oranları elde edemeyeceğinizden eminim. SecureRandom'un kendi kendine tohumlanması, eğer bulamazsa, gerçek bir entropi elde etmek için oldukça zor çalışır: seancassidy.me/wiggle-the-mouse-to-fix-the-test.html
Michael Borgwardt

114

Vikipedi'nin çok iyi bir cevabı var http://en.wikipedia.org/wiki/Universally_unique_identifier#Collisions

en az bir çarpışma olasılığının% 50 olması için üretilmesi gereken rastgele sürüm 4 UUID'lerin sayısı aşağıdaki şekilde hesaplanır: 2.71 quintillion:

...

Bu sayı, yaklaşık 85 yıl boyunca saniyede 1 milyar UUID oluşturmaya eşdeğerdir ve UUID başına 16 baytta bu çok sayıda UUID içeren bir dosya, şu anda var olan en büyük veritabanlarından birçok kez daha büyük olmak üzere yaklaşık 45 eksabayt olacaktır. yüzlerce petabayt sırası.

...

Bu nedenle, milyarlarca çoğaltma şansı olması için 103 trilyon sürüm 4 UUID oluşturulmalıdır.


56
Bu sayfadan da, "Dünyadaki her insan 600 milyon UUID'ye sahipse, bir kopya olasılığı yaklaşık% 50 olacaktır."
Jeff Axelrod

24
Bu sadece gerçek rastgelelik için geçerlidir, java UUID'leri gibi yalancı sayılar için geçerli değildir.
Markus

9
@ Markus: tamamen yanlış. İyi psödondom RNG'lerin özellikle kriptografik olarak güçlü olanlar için çarpışma olasılığı "gerçek" rastgelelikten farklı değildir.
Michael Borgwardt

6
@Eric - Sanırım iddianızı yedeklemek için yanınızda. FWIW, tip 4 UUID'lerin olasılık teorisinin olması gerektiğini söylediği yerlerde daha sık çarpışacağı tek senaryo: 1) kötü bir kripto rasgele sayı kaynağı veya 2) tehlikeye atılan bir UUID kütüphanesi.
Stephen C

13
Bu, sorulan soruya cevap vermiyor. Soru, UUID.randomUUID()belirli bir rasgele sayı üretecinin teorik şansı hakkında değil , Java'lardaki rasgeleliğin kalitesi ile ilgilidir .
kratenko

69

Paylaşacak herhangi bir tecrübesi olan var mı?

2^122Tip 4 UUID için olası değerler vardır . (Spesifikasyon, tür için 2 bit ve sürüm numarası için 4 bit daha kaybettiğinizi söylüyor.)

Saniyede 1 milyon rastgele UUID üreteceğinizi varsayarsak, yaşamınızda yinelenen bir şansın olması kaybolur. Ve yinelenen algılamak için, size karşı saniyede 1 milyon yeni UUIDs karşılaştırmanın sorunu çözmek zorundayız önceden oluşturmuş UUID tüm 1 !

Herkesin gerçek hayatta bir kopyasını yaşamış olma (yani aslında farkına varma ) şansı, çarpışmayı aramanın pratik zorluğu nedeniyle, kaybolan küçüklükten bile daha küçüktür.

Şimdi, elbette, gerçekten rastgele sayıların kaynağı değil, tipik olarak sahte bir sayı üreteci kullanacaksınız. Ancak, kriptografik güç rasgele sayılarınız için güvenilir bir sağlayıcı kullanıyorsanız, o zaman kriptografik güç olacağından ve tekrarlama olasılığının ideal (önyargısız) rasgele sayı üreteciyle aynı olacağından emin olabiliriz. .

Ancak, "bozuk" kripto rasgele sayı üreteciyle bir JVM kullanacaksanız, tüm bahisler kapalıdır. (Bu, bazı sistemlerde "entropi kıtlığı" sorunları için bazı geçici çözümleri de içerebilir. Veya birisinin JRE'nizle sisteminizde veya yukarı akışta uğraşma olasılığı.)


1 - Anonim bir yorumcu tarafından önerildiği gibi "bir tür ikili btree" kullandığınızı varsayarsak, her UUID'nin, O(NlogN)bitlerin Ndüşük yoğunluğu ve rastgele dağılımını varsayan farklı UUID'leri temsil etmek için RAM bellek parçalarına ihtiyacı olacaktır . Şimdi bunu 1.000.000 ile ve denemeyi yapacağınız saniye sayısını çarpın. Bunun yüksek kaliteli RNG çarpışmalarını test etmek için gereken süre boyunca pratik olduğunu düşünmüyorum. (Varsayımsal) akıllı temsillerle bile değil.


4
"(Ve kopyayı tespit etmek için, saniyede 1 milyon yeni UUID'yi daha önce oluşturduğunuz tüm UUID'lerle karşılaştırma sorununu çözmeniz gerekir!)" - bu bölüm, uuid'lerinizi bazılarında sakladığınızı varsayarak nispeten basittir. bir tür ikili ağaç yapısı, yeni uuid başına sadece bir ağaç iniş olurdu. Önceden oluşturulmuş tüm uuidlerle tek tek karşılaştırmanız gerekmez.
user467257

20

Ben bir uzman değilim, ama yıllarca Java'nın rasgele sayı üreticisine bakacak kadar zeki insan olduğunu varsayıyorum. Bu nedenle, rastgele UUID'lerin de iyi olduğunu varsayabilirim. Bu yüzden gerçekten teorik çarpışma olasılığına sahip olmalısınız (bu, tüm olası UUID'ler için yaklaşık 1: 3 × 10 ^ 38'dir . Herkes bunun rastgele UUID'ler için nasıl değiştiğini biliyor mu 1/(16*4)?

Pratik tecrübelerime göre, şimdiye kadar hiç çarpışma görmedim. Muhtemelen ilkini aldığım gün şaşırtıcı derecede uzun sakal bırakacağım;)


10
Vikipedi'den: Başka bir deyişle, sadece önümüzdeki 100 yıl için saniyede 1 milyar UUID oluşturduktan sonra, sadece bir kopya oluşturma olasılığı yaklaşık% 50 olacaktır.
MaVRoSCy

1
Aslında wikipedia önümüzdeki 85 yıl için diyor ... güvenmiyorum diyorum, bir yerlerde sizinle aynı UUID üretti
smac89

12

Eski bir işverenimizde rastgele bir uuid içeren benzersiz bir sütun vardı. Konuşlandırıldıktan sonraki ilk hafta bir çarpışma yaşadık. Tabii, oranlar düşük ama sıfır değil. Bu nedenle Log4j 2, UuidUtil.getTimeBasedUuid içeriyor. Tek bir sunucuda 10.000'den fazla UUID / milisaniyeden fazla üretmediğiniz sürece 8.925 yıl boyunca benzersiz bir UUID üretecektir.


2
Evet. Ancak soru rastgele (yani tip-4) UUID'leri soruyor.
Stephen C

1
Bir çarpışma olasılığı hakkında sorular soruyor. Bunun anlamı onlardan kaçınmak istediğinden emin olmaktır.
rgoers

1
(Çarpışma büyük olasılıkla PRNG'lerin tohumlanması için rastgele bir rastgele kaynağa bağlıydı. Sanırım saf şanstan kaynaklanabileceğini sanıyordum.)
Stephen C

9

UUID'ler için orijinal nesil şeması, UUID sürümünü, UUID'yi oluşturan bilgisayarın MAC adresiyle ve Batı'da Gregoryen takviminin benimsenmesinden bu yana 100 nanosaniye aralıklarla birleştirmekti. Uzayda tek bir noktayı (bilgisayar) ve zamanı (aralık sayısı) temsil ederek, değerlerde çarpışma olasılığı etkin bir şekilde sıfırdır.


1
Bu açıklama beni pratikte çarpışmaları görmemek konusunda iyimser kılıyor. Bu ifade için herhangi bir referansa işaret edebilir misiniz (bazı kaynak kodları daha iyi olurdu)?
Dragan Marjanović

Bunu ietf.org/rfc/rfc4122.txt özelliklerinde buldu . Yine de uygulamayı görmek harika olurdu.
Dragan Marjanović

1
Ancak bu şema Java'nın uyguladığı şey değildir. Java, saf rasgele olan ve MAC adresi veya saati içermeyen tip 4 UUID'yi uygular. Bu arada, MAC adresinizi seçebileceğiniz birçok fiziksel ve sanal cihaz olduğundan, orijinal algoritma benzersizliği garanti etmez.
Søren Boisen

8

Yanıtların çoğu,% 50'lik bir çarpışma şansına ulaşmak için kaç tane UUID'nin oluşturulması gerektiğini tartışıyor. Ancak, çarpışmanın (neredeyse) imkansız olması gereken bir uygulama için% 50,% 25 ve hatta% 1 çarpışma şansı değersizdir.

Programcılar rutin olarak meydana gelebilecek ve meydana gelebilecek diğer olayları "imkansız" olarak reddediyor mu?

Bir diske veya belleğe veri yazıp tekrar okuduğumuzda, verilerin doğru olduğunu kabul ederiz. Herhangi bir bozulmayı tespit etmek için cihazın hata düzeltmesine güveniyoruz. Ancak saptanamayan hataların olasılığı aslında 2-50 civarındadır .

Rastgele UUID'lere benzer bir standart uygulamak mantıklı değil mi? Bunu yaparsanız, yaklaşık 100 milyar rastgele UUID koleksiyonunda "imkansız" bir çarpışmanın mümkün olduğunu göreceksiniz (2 36.5 ).

Bu bir astronomik sayıdır, ancak ulusal bir sağlık sisteminde ayrıntılı faturalandırma veya yüksek frekans sensör verilerinin çok sayıda cihaza kaydedilmesi gibi uygulamalar kesinlikle bu sınırlara çarpabilir. Bir sonraki Otostopçu Rehberi Galaksiye yazıyorsanız, her makaleye UUID atamaya çalışmayın!


Bir karşılaştırma noktası olarak, bir Powerball ikramiyesini kazanma şansı 300 milyonda 1'dir, ancak 10 ila 20 milyon bilet satışı tipiktir. Mesele şu ki, birçok insan "imkansız" ı yüz milyonda bir şanstan daha az bir şey olarak tanımlamaktadır .
erickson

4

Cevapların çoğu teoriye odaklandığından, pratik bir test yaparak tartışmaya bir şeyler ekleyebileceğimi düşünüyorum. Veritabanımda Java 8 UUID.randomUUID () kullanılarak oluşturulmuş yaklaşık 4,5 milyon UUID var. Aşağıdakiler sadece öğrendiğim bazıları:

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

Gerçekten rastgele olsaydı, bu tür benzer UUID'lere sahip olma olasılığı oldukça düşük olurdu (düzenlemeye bakın), çünkü sadece 4,5 milyon girişi düşünüyoruz. Bu işlev değil sahip çarpışmaların açısından iyi olmasına rağmen Yani, benim için o görünmüyor o da teoride olacağı gibi iyi.

Düzenle :

Pek çok insan bu cevabı anlamıyor gibi görünüyor, bu yüzden fikrimi netleştireceğim: Benzerliklerin "küçük" ve tam bir çarpışmadan uzak olduğunu biliyorum. Ancak, sadece Java'nın UUID.randomUUID () gerçek soru rastgele gerçek bir sayı üreteci ile karşılaştırmak istedim.

Gerçek bir rasgele sayı üretecinde, son durumun meydana gelme olasılığı =% 0.007 civarında olacaktır . Bu nedenle, sonucumun geçerli olduğunu düşünüyorum.

Formül bu wiki makalesinde açıklanmıştır. En.wikipedia.org/wiki/Birthday_problem


6
Bu doğru değil. Bu tür benzerlikler, 4.5M sıvılar üzerinde gerçek bir rastgele sayı üreteci ile bile ortaya çıkacaktır. Verdiğiniz UUID'ler arasındaki benzerlikler küçük ve uzak, tam bir çarpışmadan uzak.
user3711864

Benzerliklerin "küçük" ve tam bir çarpışmadan uzak olduğu konusunda tamamen katılıyorum. Ancak, sadece Java'nın UUID.randomUUID () gerçek bir rastgele sayı üreteci ile karşılaştırmak istedim (bu soru). Bazı hesaplamalarda, gerçek bir rasgele sayı üretecinde, son durumun gerçekleşme olasılığının 1-e ^ (- 4500000 ^ 2 / (2 * 36 ^ 11)) = 0.007% = 1 13k. Çok şanslı olmalıyım :)
André Pinheiro

1
4.5 milyon ürün ve 13 bin şansın 1'i ile, böyle bir kısmi çarpışma 346 kez beklenemez mi?
Ben Lee

Hayır @ BenLee, 4.5 milyon eşyanın olduğu düşünülerek o olayın gerçekleşme olasılığını hesapladım. Her ürün için 13 k'da 1 şansı yok. Kullandığım formül bu wiki makalesinde bulunabilir. En.wikipedia.org/wiki/Birthday_problem
André Pinheiro

2
Beklentiniz neydi? Benzer değil, değil mi?
Koray Tugay

3

Geçen yıl piyango oynuyorum ve hiç kazanmadım .... ama piyangonun kazananları var gibi görünüyor ...

doc: http://tools.ietf.org/html/rfc4122

Tip 1: uygulanmadı. uuid aynı anda üretilirse çarpışma mümkündür. impl bu sorunu atlamak için yapay olarak senkronize olabilir.

Tip 2: asla bir uygulama görmeyin.

Tip 3: Md5 karma: olası çarpışma (128 bit-2 teknik bayt)

Tip 4: Rastgele: Çarpışma mümkün (piyango olarak). jdk6 impl "PRNG algoritması geliştirici tarafından seçilmez ve" bir "zayıf" PRNG algo kullanmaya zorlayabilirsiniz çünkü "gerçek" güvenli rasgele kullanmayın unutmayın. Yani UUID'niz tahmin edilebilir.

Tip 5: sha1 karması: uygulanmadı: çarpışma mümkün (160 bit-2 teknik bayt)


4
Piyangoyu kazanma olasılığı belki 10 veya 100 milyonda (10 ^ 7 veya 10 ^ 8) ya da bunun gibi bir şeydir. 128 bit rasgele sayı ile çarpışma olasılığı 3.4 * 10 ^ 28'dir. Bana her zaman bir piyango bileti ver!
Stephen C

0

Java'nın rastgele UUID'sini bir yıldan fazla bir süredir uygulamamızda kullanıyoruz ve bunu çok kapsamlı bir şekilde yapıyoruz. Ama biz asla çarpışmaya rastlayamayız.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.