UUID.randomUUID của Java tốt như thế nào?


311

Tôi biết rằng các UUID ngẫu nhiên có xác suất va chạm rất, rất, rất thấp trong lý thuyết, nhưng tôi tự hỏi, trong thực tế, Java tốt như thế nào randomUUID()khi không có va chạm? Có ai có kinh nghiệm để chia sẻ?


10
Theo kinh nghiệm của tôi, tôi chưa bao giờ thấy một vụ va chạm nào ;-)
Thilo

4
Các thuật toán được chỉ định trong RFC1422: ietf.org/rfc/rfc4122.txt
skaffman

8
@skaffman: RFC hoàn toàn không nói gì về thuật toán được sử dụng để tạo các chữ số ngẫu nhiên.
Michael Borgwardt

4
Vì đây là một câu hỏi kết thúc mở hơn, tôi đoán tôi sẽ không đánh dấu bất kỳ câu trả lời nào là câu trả lời đúng; thay vào đó, tôi sẽ bỏ một phiếu cho mỗi câu trả lời mà tôi cho là hay :)
Alvin

5
Từ wikipedia: ... Nói cách khác, chỉ sau khi tạo 1 tỷ UUID mỗi giây trong 100 năm tiếp theo, xác suất tạo ra chỉ một bản sao sẽ là khoảng 50%.
MaVRoSCy

Câu trả lời:


168

UUID sử dụng java.security.SecureRandom, được cho là "mạnh về mặt mật mã". Mặc dù việc triển khai thực tế không được chỉ định và có thể khác nhau giữa các JVM (có nghĩa là bất kỳ câu lệnh cụ thể nào được đưa ra chỉ hợp lệ cho một JVM cụ thể), nhưng bắt buộc đầu ra phải vượt qua kiểm tra trình tạo số ngẫu nhiên thống kê.

Việc triển khai có thể chứa các lỗi tinh vi phá hỏng tất cả điều này (xem lỗi tạo khóa OpenSSH) nhưng tôi không nghĩ có bất kỳ lý do cụ thể nào để lo lắng về tính ngẫu nhiên của Java UUID.


34
"Luôn luôn có thể thực hiện để chứa các lỗi tinh vi ..." - Hoặc (tặng mũ thiếc-lá) ... các lỗi tinh vi có chủ ý. <:-)
Stephen C

25
Sức mạnh mật mã hoàn toàn không liên quan đến câu hỏi về sự va chạm.
osa

14
@osa: Không tạo ra va chạm (nhiều hơn mong đợi từ sự ngẫu nhiên hoàn hảo) là yêu cầu chất lượng thấp nhất đối với RNG, trong khi cường độ mật mã là cao nhất. Nói cách khác, một RNG mạnh về mật mã chắc chắn sẽ không tạo ra nhiều va chạm hơn dự kiến.
Michael Borgwardt

3
Tuy nhiên, có thể hữu ích khi lưu ý rằng nếu bạn ví dụ chạy JVM tạo ra các UUID bên trong blog.vmware.com/cto/ , bạn có thể sẽ gặp nhiều va chạm. Tất cả các RNG phần mềm đều là PRNG và cuối cùng chúng chỉ tốt như nguồn entropy của chúng; hai PRNG được tạo mầm giống hệt nhau cũng sẽ hoạt động giống hệt nhau và điều đó có thể xảy ra một cách đáng ngạc nhiên thường xuyên với các thiết lập máy chủ trùng lặp, chính xác trùng lặp và quy trình khởi động.
user508633

@ user508633: Tôi thực sự mong đợi có được tỷ lệ va chạm 100% trong trường hợp cụ thể đó, nhưng đó là một trường hợp rất cụ thể thực sự vượt xa "các thiết lập máy chủ nhất quán, trùng lặp chính xác và quy trình khởi động". Tôi khá chắc chắn rằng bạn sẽ không nhận được bất kỳ tỷ lệ va chạm nào tăng lên nếu bạn chỉ nhân bản một máy ảo và chạy nó bình thường. Việc tự khởi động SecureRandom cố gắng khá nhiều để có được một số entropy thực sự, đến mức chặn thực thi nếu nó không thể tìm thấy bất kỳ: seancassidy.me/wiggle-the-mouse-to-fix-the-test.html
Michael Borgwardt

114

Wikipedia có một câu trả lời rất hay http://en.wikipedia.org/wiki/Universally_unique_identifier#Collutions

số lượng UUID phiên bản ngẫu nhiên 4 cần được tạo để có xác suất 50% ít nhất một vụ va chạm là 2,71 triệu, được tính như sau:

...

Con số này tương đương với việc tạo ra 1 tỷ UUID mỗi giây trong khoảng 85 năm và một tệp chứa nhiều UUID này, ở mức 16 byte mỗi UUID, sẽ khoảng 45 exabyte, lớn hơn nhiều lần so với cơ sở dữ liệu lớn nhất hiện có. thứ tự hàng trăm petabyte.

...

Do đó, để có một cơ hội nhân đôi một tỷ, phải tạo ra 103 nghìn tỷ UUID phiên bản 4 nghìn tỷ.


56
Tôi cũng xin trích dẫn từ trang đó, "Xác suất của một bản sao sẽ là khoảng 50% nếu mỗi người trên trái đất sở hữu 600 triệu UUID."
Jeff Axelrod

24
Điều này chỉ đúng với tính ngẫu nhiên thực sự, không đúng với số giả ngẫu nhiên như UUID javas.
Markus

9
@Markus: sai hoàn toàn. Xác suất va chạm đối với các RNG giả danh tốt, đặc biệt là những người mạnh về mật mã, không khác gì ngẫu nhiên "thật".
Michael Borgwardt

6
@Eric - Tôi nghĩ rằng trách nhiệm thuộc về bạn để sao lưu khẳng định của bạn. F.
Stephen C

13
Điều này không trả lời câu hỏi. Câu hỏi là về chất lượng của tính ngẫu nhiên trong Java UUID.randomUUID(), chứ không phải về cơ hội lý thuyết cho một trình tạo số ngẫu nhiên hoàn hảo nhất định.
kratenko

69

Có ai có kinh nghiệm để chia sẻ?

2^122các giá trị có thể cho UUID loại 4. (Thông số kỹ thuật nói rằng bạn mất 2 bit cho loại và thêm 4 bit cho số phiên bản.)

Giả sử rằng bạn đã tạo ra 1 triệu UUID ngẫu nhiên một giây, khả năng trùng lặp xảy ra trong cuộc đời của bạn sẽ rất nhỏ. Và để phát hiện bản sao, bạn phải giải quyết vấn đề so sánh 1 triệu UUID mới mỗi giây so với tất cả các UUID bạn đã tạo trước đó 1 !

Cơ hội mà bất cứ ai đã trải qua (tức là thực sự nhận thấy ) một bản sao trong cuộc sống thực thậm chí còn nhỏ hơn cả nhỏ bé ... bởi vì khó khăn thực tế trong việc tìm kiếm va chạm.

Bây giờ tất nhiên, thông thường bạn sẽ sử dụng một trình tạo số giả ngẫu nhiên, không phải là nguồn của các số thực sự ngẫu nhiên. Nhưng tôi nghĩ rằng chúng ta có thể tin tưởng rằng nếu bạn đang sử dụng một nhà cung cấp đáng tin cậy cho các số ngẫu nhiên về cường độ mã hóa của mình, thì đó sẽ là cường độ mã hóa và xác suất lặp lại sẽ giống như đối với trình tạo số ngẫu nhiên (không sai lệch) lý tưởng .

Tuy nhiên, nếu bạn sử dụng một JVM với trình tạo số ngẫu nhiên "bị hỏng", tất cả các cược đều bị tắt. (Và điều đó có thể bao gồm một số cách giải quyết cho các vấn đề "thiếu entropy" trên một số hệ thống. Hoặc khả năng ai đó đã sửa chữa JRE của bạn, trên hệ thống của bạn hoặc ngược dòng.)


1 - Giả sử rằng bạn đã sử dụng "một loại btree nhị phân" nào đó theo đề xuất của một nhà bình luận ẩn danh, mỗi UUID sẽ cần O(NlogN)các bit bộ nhớ RAM để biểu diễn Ncác UUID khác nhau giả sử mật độ thấp và phân phối ngẫu nhiên các bit. Bây giờ nhân số đó với 1.000.000 và số giây bạn sẽ chạy thử nghiệm. Tôi không nghĩ rằng điều đó là thực tế trong khoảng thời gian cần thiết để kiểm tra sự va chạm của RNG chất lượng cao. Thậm chí không có đại diện (giả thuyết) thông minh.


4
"(Và để phát hiện bản sao, bạn phải giải quyết vấn đề so sánh 1 triệu UUID mới mỗi giây với tất cả các UUID bạn đã tạo trước đó!)" - phần đó tương đối đơn giản khi cho rằng bạn đã lưu trữ uuids của mình trong một số loại cấu trúc cây nhị phân, nó sẽ chỉ là một cây gốc cho mỗi uuid mới. Bạn sẽ không cần phải thực sự so sánh nó với tất cả các uuids được tạo trước đó.
dùng467257

20

Tôi không phải là một chuyên gia, nhưng tôi cho rằng đủ người thông minh đã xem xét trình tạo số ngẫu nhiên của Java trong nhiều năm qua. Do đó, tôi cũng cho rằng UUID ngẫu nhiên là tốt. Vì vậy, bạn nên thực sự có xác suất va chạm lý thuyết (khoảng 1: 3 × 10 ^ 38 cho tất cả các UUID có thể. Có ai biết điều này thay đổi như thế nào đối với chỉ các UUID ngẫu nhiên không? Có phải 1/(16*4)ở trên không?)

Từ kinh nghiệm thực tế của tôi, tôi chưa bao giờ thấy bất kỳ va chạm nào cho đến nay. Có lẽ tôi đã mọc một bộ râu dài đáng kinh ngạc vào ngày tôi có được cái đầu tiên;)


10
Từ wikipedia: ... Nói cách khác, chỉ sau khi tạo 1 tỷ UUID mỗi giây trong 100 năm tiếp theo, xác suất tạo ra chỉ một bản sao sẽ là khoảng 50%.
MaVRoSCy

1
Trên thực tế, wikipedia nói rằng trong 85 năm tới ... Tôi nói đừng tin vào điều đó, một người nào đó đã tạo ra UUID giống như bạn
smac89

12

Tại một công ty cũ, chúng tôi có một cột duy nhất chứa một uuid ngẫu nhiên. Chúng tôi đã có một vụ va chạm vào tuần đầu tiên sau khi nó được triển khai. Chắc chắn, tỷ lệ cược thấp nhưng chúng không bằng không. Đó là lý do tại sao Log4j 2 chứa UuidUtil.getTimeBasingUuid. Nó sẽ tạo ra một UUID duy nhất trong 8,925 năm miễn là bạn không tạo ra hơn 10.000 UUID / mili giây trên một máy chủ.


2
Đúng. Nhưng câu hỏi là hỏi về UUID ngẫu nhiên (tức là loại 4).
Stephen C

1
Đó là hỏi về khả năng bị va chạm. Hàm ý là anh ta muốn chắc chắn tránh chúng.
tham gia

1
(Vụ va chạm rất có thể là do một nguồn ngẫu nhiên bị phá vỡ cho việc gieo hạt PRNG. Tôi nghĩ rằng tôi đoán rằng có thể đó là do cơ hội thuần túy.)
Stephen C

9

Lược đồ thế hệ ban đầu cho các UUID là nối phiên bản UUID với địa chỉ MAC của máy tính đang tạo UUID và với số lượng khoảng 100 nano giây kể từ khi áp dụng lịch Gregorian ở phương Tây. Bằng cách biểu thị một điểm duy nhất trong không gian (máy tính) và thời gian (số lượng khoảng), khả năng xảy ra va chạm trong các giá trị là không.


1
Lời giải thích này khiến tôi lạc quan không thấy va chạm trong thực tế. Bạn có thể chỉ ra bất kỳ tham chiếu nào cho tuyên bố này (một số mã nguồn sẽ còn tốt hơn)?
Dragan Marjanović

Tìm thấy điều này trong thông số kỹ thuật ietf.org/rfc/rfc4122.txt . Tuy nhiên sẽ là tuyệt vời để xem thực hiện.
Dragan Marjanović

1
Tuy nhiên, lược đồ đó không phải là những gì Java thực hiện. Java triển khai UUID loại 4, hoàn toàn ngẫu nhiên và không bao gồm địa chỉ MAC hoặc thời gian. Ngẫu nhiên, vì hiện nay có nhiều thiết bị vật lý và ảo nơi bạn có thể chọn địa chỉ MAC của mình, thuật toán ban đầu không đảm bảo tính duy nhất.
Søren Boisen

8

Nhiều câu trả lời thảo luận về việc sẽ tạo ra bao nhiêu UUID để đạt được 50% khả năng xảy ra va chạm. Nhưng khả năng va chạm 50%, 25% hoặc thậm chí 1% là vô giá trị đối với một ứng dụng mà việc va chạm phải (hầu như) là không thể.

Các lập trình viên có thường xuyên loại bỏ là "không thể" các sự kiện khác có thể và có thể xảy ra không?

Khi chúng ta ghi dữ liệu vào đĩa hoặc bộ nhớ và đọc lại, chúng ta sẽ cho rằng dữ liệu là chính xác. Chúng tôi dựa vào sửa lỗi của thiết bị để phát hiện bất kỳ tham nhũng nào. Nhưng khả năng xảy ra lỗi không bị phát hiện là khoảng 2 -50 .

Sẽ không hợp lý nếu áp dụng một tiêu chuẩn tương tự cho các UUID ngẫu nhiên? Nếu bạn làm như vậy, bạn sẽ thấy rằng có thể xảy ra va chạm "không thể" trong bộ sưu tập khoảng 100 tỷ UUID ngẫu nhiên (2 36,5 ).

Đây là một con số thiên văn, nhưng các ứng dụng như thanh toán từng khoản trong hệ thống chăm sóc sức khỏe quốc gia hoặc ghi dữ liệu cảm biến tần số cao trên một mảng lớn các thiết bị chắc chắn có thể gặp phải những giới hạn này. Nếu bạn đang viết Hướng dẫn của Hitchhiker tiếp theo cho Galaxy, đừng cố gán UUID cho mỗi bài viết!


Để so sánh, cơ hội trúng giải độc đắc Powerball là 1 trên 300 triệu, nhưng doanh số từ 10 đến 20 triệu vé là điển hình. Vấn đề là nhiều người định nghĩa "không thể" là một cái gì đó ít hơn một cơ hội trong hàng trăm triệu.
erickson

4

Vì hầu hết các câu trả lời tập trung vào lý thuyết, tôi nghĩ rằng tôi có thể thêm điều gì đó vào cuộc thảo luận bằng cách đưa ra một bài kiểm tra thực tế tôi đã làm. Trong cơ sở dữ liệu của tôi, tôi có khoảng 4,5 triệu UUID được tạo bằng Java 8 UUID.randomUUID (). Những cái sau đây chỉ là một số tôi tìm ra:

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

Nếu nó thực sự ngẫu nhiên, xác suất có các loại UUID tương tự này sẽ thấp đáng kể (xem chỉnh sửa), vì chúng tôi chỉ xem xét 4,5 triệu mục. Vì vậy, mặc dù chức năng này là tốt, về mặt không có va chạm, đối với tôi nó không có vẻ rằng tốt vì nó sẽ là về mặt lý thuyết.

Chỉnh sửa :

Rất nhiều người dường như không hiểu câu trả lời này vì vậy tôi sẽ làm rõ quan điểm của mình: Tôi biết rằng những điểm tương đồng là "nhỏ" và khác xa với một vụ va chạm hoàn toàn. Tuy nhiên, tôi chỉ muốn so sánh UUID.randomUUID () của Java với một trình tạo số ngẫu nhiên thực sự, đó là câu hỏi thực tế.

Trong một trình tạo số ngẫu nhiên thực sự, xác suất của trường hợp cuối cùng xảy ra sẽ vào khoảng = 0,007%. Do đó, tôi nghĩ rằng kết luận của tôi đứng.

Công thức được giải thích trong bài viết wiki này en.wikipedia.org/wiki/BISS_propet


6
Đây không phải là sự thật. Những loại tương tự này sẽ phát sinh ngay cả với một trình tạo số ngẫu nhiên thực sự trên các uuids 4,5M. Sự tương đồng giữa các UUID mà bạn đưa ra rất nhỏ và xa, thật xa so với một vụ va chạm hoàn toàn.
dùng3711864

Tôi hoàn toàn đồng ý với bạn rằng những điểm tương đồng là "nhỏ" và khác xa với một vụ va chạm hoàn toàn. Tuy nhiên, tôi chỉ muốn so sánh UUID.randomUUID () của Java với trình tạo số ngẫu nhiên thực sự (đây là câu hỏi). Với một số tính toán chúng ta có thể thấy rằng, trong một trình tạo số ngẫu nhiên thực sự, xác suất của trường hợp cuối cùng xảy ra sẽ vào khoảng 1-e ^ (- 4500000 ^ 2 / (2 * 36 ^ 11)) = 0,007% = 1 trong một 13k. Tôi sẽ phải rất may mắn :)
André Pinheiro

1
Với 4,5 triệu vật phẩm và cơ hội 1 trong 13 nghìn, liệu một vụ va chạm một phần như thế có được mong đợi 346 lần không?
Ben Lee

Không có @BenLee, tôi đã tính xác suất của sự kiện đó xảy ra khi xem xét rằng chúng tôi có 4,5 triệu mặt hàng. Đây không phải là cơ hội 1 trong 13k xảy ra cho mỗi mục. Công thức tôi đã sử dụng có thể được tìm thấy trong bài viết wiki này en.wikipedia.org/wiki/BISS_probols
André Pinheiro

2
Mong đợi của bạn là gì? Tương tự là không giống nhau, phải không?
Koray Tugay

3

Tôi chơi xổ số năm ngoái và tôi chưa bao giờ thắng .... nhưng dường như xổ số có người chiến thắng ...

tài liệu: http://tools.ietf.org/html/rfc4122

Loại 1: không được thực hiện. va chạm là có thể nếu uuid được tạo ra cùng một lúc. Im có thể được đồng bộ hóa một cách giả tạo để bỏ qua vấn đề này.

Loại 2: không bao giờ thấy việc thực hiện.

Loại 3: băm md5: có thể va chạm (byte kỹ thuật 128 bit-2)

Loại 4: ngẫu nhiên: có thể va chạm (như xổ số). lưu ý rằng hàm jdk6 không sử dụng ngẫu nhiên an toàn "đúng" vì thuật toán PRNG không được nhà phát triển chọn và bạn có thể buộc hệ thống sử dụng thuật toán PRNG "kém". Vì vậy, UUID của bạn là có thể dự đoán.

Loại 5: băm sha1: không được triển khai: có thể va chạm (byte kỹ thuật 160 bit-2)


4
Xác suất trúng xổ số có thể là một trong 10 hoặc 100 triệu (10 ^ 7 hoặc 10 ^ 8) hoặc đại loại như thế. Xác suất va chạm với số ngẫu nhiên 128 bit là 3,4 * 10 ^ 28. Hãy cho tôi một vé xổ số bất cứ lúc nào!
Stephen C

0

Chúng tôi đã sử dụng UUID ngẫu nhiên của Java trong ứng dụng của chúng tôi trong hơn một năm và điều đó rất rộng rãi. Nhưng chúng tôi không bao giờ đi qua có va chạm.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.