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ẻ?
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ẻ?
Câu trả lời:
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.
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ỷ.
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.
Có ai có kinh nghiệm để chia sẻ?
Có 2^122
cá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 N
cá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.
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;)
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ủ.
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.
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!
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
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)