JavaのUUID.randomUUIDはどの程度優れていますか?


311

ランダム化されたUUIDは、理論的には衝突の可能性が非常に低いことを知っていますが、実際にrandomUUID()は、衝突がないという点でJava はどれほど優れているのでしょうか。誰かが共有する経験がありますか?


10
私の経験では、衝突は見たことがありません;-)
Thilo

4
アルゴリズムはRFC1422で指定されています: ietf.org/rfc/rfc4122.txt
skaffman

8
@skaffman:RFCは、ランダムな数字を生成するために使用されるアルゴリズムについてまったく何も述べていません。
Michael Borgwardt

4
これはより自由回答形式の質問なので、正解としてマークを付けることはないと思います。代わりに、私が良いと思う答えのそれぞれに1票ずつ投票します:)
Alvin

5
ウィキペディアから:...言い換えると、次の100年間、毎秒10億個のUUIDを生成した後にのみ、複製を1つだけ作成する確率は約50%になります。
MaVRoSCy 2012

回答:


168

UUIDはを使用しますjava.security.SecureRandom。これは「暗号的に強力」であると想定されています。実際の実装は指定されておらず、JVM間で異なる可能性があります(つまり、作成された具体的なステートメントは1つの特定のJVMに対してのみ有効です)、出力は統計乱数ジェネレータテストに合格する必要があります。

実装がこれを台無しにする微妙なバグを含むことは常に可能ですが(OpenSSHキー生成のバグを参照)、Java UUIDのランダム性について心配する具体的な理由はないと思います。


34
「実装が微妙なバグを含むことは常に可能です...」 -または(ブリキの帽子を被る)...意図的な微妙な欠陥。<:-)
スティーブンC

25
暗号強度は、衝突の問題にはまったく関係ありません。
osa

14
@osa:完全なランダム性から予想される以上の衝突を発生させないことは、RNGの最低品質要件であり、暗号強度は最高です。言い換えると、暗号的に強力なRNGは、予想以上に多くの衝突を引き起こしません。
Michael Borgwardt、2015年

3
ただし、たとえばblogs.vmware.com/cto/…内でUUIDを生成するJVMを実行すると、衝突が多数発生することに注意してください。すべてのソフトウェアRNGはPRNGであり、最終的にはエントロピーのソースと同じくらい優れています。シードが同じである2つのPRNGも同じように動作します。これは、一貫した、完全に重複したサーバーのセットアップと起動手順で驚くほど頻繁に発生する可能性があります。
user508633

@ user508633:実際には、この特定のケースでは100%の衝突率が得られると予想しますが、「一貫性のある完全に重複したサーバーのセットアップと起動手順」をはるかに超える非常に特殊なケースです。VMのクローンを作成してそれを正常に実行しただけでは、衝突率が増加しないと確信しています。SecureRandomの自己シードは、実際のエントロピーを取得するためにかなり懸命に試行し、エントロピーが見つからない場合は実行をブロックします。seancassidy.me
Michaelボルグワート

114

ウィキペディアには非常に良い答えがあります http://en.wikipedia.org/wiki/Universally_unique_identifier#Collisions

少なくとも1つの衝突の50%の確率を持つために生成する必要があるバージョン4のランダムなUUIDの数は、次のように計算されて2.71千兆です。

...

この数は、約85年間、1秒あたり10億のUUIDを生成することに相当し、UUIDあたり16バイトのこの多くのUUIDを含むファイルは、約45エクサバイトであり、現在存在する最大のデータベースよりも何倍も大きい数百ペタバイトのオーダー。

...

したがって、10億分の1の重複の可能性があるためには、103兆のバージョン4 UUIDを生成する必要があります。


56
私はまた、そのページから引用します。「地球上のすべての人が6億のUUIDを所有している場合、1つの重複の確率は約50%です。」
ジェフアクセルロッド

24
これは真のランダム性にのみ当てはまり、javas UUIDのような疑似乱数には当てはまりません。
マーカス

9
@Markus:完全に間違っています。優れた疑似ランダムRNGの特に暗号学的に強力なRNGの衝突の確率は、「真の」ランダム性と同じです。
Michael Borgwardt 2013

6
@エリック-あなたの主張をバックアップする責任はあなたにあると思います。FWIW、タイプ4 UUIDがより頻繁に衝突する可能性があると私が考えることができる唯一のシナリオは、確率理論により次のとおりであるはずであるということです:1)暗号乱数の悪いソース、または2)侵害されたUUIDライブラリ。
スティーブンC

13
これは尋ねられた質問には答えません。問題は、Javaのランダム性の質UUID.randomUUID()についてであり、与えられた完全な乱数ジェネレーターの理論的な可能性についてではありません。
kratenko

69

誰かが共有する経験がありますか?

2^122タイプ4 UUIDには可能な値があります。(仕様によると、型には2ビット、バージョン番号にはさらに4ビットが失われます。)

1秒間に100万個のランダムなUUIDを生成すると仮定すると、存続期間中に重複が発生する可能性はほとんどありません。重複を検出するには、毎秒100万の新しいUUID を、以前に生成したすべての UUIDと比較するという問題を解決する必要があります1

現実の世界で誰かが重複を経験した(つまり、実際に気付いた)可能性は、衝突を探すのが実際的に難しいため、無視できるほど小さいものよりもさらに小さくなります。

もちろん、通常は、真の乱数のソースではなく、疑似乱数ジェネレータを使用します。しかし、暗号強度の乱数に信用できるプロバイダーを使用している場合、それ暗号強度となり、繰り返しの確率は理想的な(バイアスされていない)乱数ジェネレーターと同じになると確信できます。 。

ただし、「壊れた」暗号乱数ジェネレーターでJVMを使用する場合、すべての賭けは無効になります。(これには、一部のシステムでの「エントロピー不足」問題の回避策の一部が含まれる場合があります。または、誰かがシステムまたはアップストリームでJREをいじくり回している可能性があります。)


1-匿名のコメンターによって提案された「ある種のバイナリbtree」を使用したとすると、各UUIDは、O(NlogN)ビットのN低密度とランダムな分布を想定して、個別のUUID を表すためにRAMメモリのビットを必要とします。ここで、1,000,000と実験を実行する秒数を掛けます。これは、高品質のRNGの衝突をテストするために必要な時間の長さでは実用的ではないと思います。(仮説的な)巧妙な表現でさえも。


4
"(そして重複を検出するには、毎秒100万の新しいUUIDを以前に生成したすべてのUUIDと比較する問題を解決する必要があります!)"-一部のuuidを格納していると仮定すると、その部分は比較的簡単です。バイナリツリー構造の一種で、新しいUUIDごとに1つのツリーの降下になります。以前に生成されたすべてのUUIDに対して実際に個別に比較する必要はありません。
user467257

20

私は専門家ではありませんが、Javaの乱数発生器を長年見てきた賢い人たちだと思います。したがって、ランダムなUUIDが良いと私は思います。したがって、理論的な衝突確率が実際にあるはずです(可能なすべてのUUIDで約1:3×10 ^ 38です。ランダムなUUIDでのみこれがどのように変わるか知っています1/(16*4)か?上記のものですか?)

私の実際の経験から、これまで衝突は見たことがありません。最初のひげを手にした日には、おそらく驚くほど長いひげが生えたでしょう。


10
ウィキペディアから:...言い換えると、次の100年間、毎秒10億個のUUIDを生成した後にのみ、複製を1つだけ作成する確率は約50%になります。
MaVRoSCy 2012

1
実際、ウィキペディアはそれが次の85年間だと言っています...私はそれを当てにしないでください、誰かがあなたと同じUUIDを生成しました
smac89

12

以前の雇用主には、ランダムなuuidを含む一意の列がありました。配備後最初の1週間で衝突が発生しました。確かに、オッズは低いですが、ゼロではありません。そのため、Log4j 2にはUuidUtil.getTimeBasedUuidが含まれています。単一のサーバーで10,000を超えるUUID /ミリ秒を生成しない限り、8,925年間一意のUUIDが生成されます。


2
はい。しかし、問題はランダム(つまり、タイプ4)のUUIDについて尋ねることです。
スティーブンC

1
衝突の可能性について尋ねています。含意は、彼がそれらを避けることを確実にしたいということです。
rgoers 2017年

1
(この衝突は、PRNGのシードのランダム性のソースが壊れていたことが原因である可能性が高いです。純粋なチャンスが原因であった可能性があると思います。)
スティーブンC

9

UUIDの元の生成方式は、UUIDバージョンを、UUIDを生成しているコンピューターのMACアドレスと、西洋でのグレゴリオ暦の採用以来の100ナノ秒間隔の数と連結することでした。空間(コンピュータ)と時間(間隔の数)の単一の点を表すことにより、値の衝突の可能性は事実上ゼロになります。


1
この説明により、衝突が実際に発生しないように楽観的になります。このステートメントの参照を指すことができますか(一部のソースコードはさらに優れています)。
DraganMarjanović2018

これはスペックietf.org/rfc/rfc4122.txtで見つかりました。それにもかかわらず、実装を見ることは素晴らしいことです。
DraganMarjanović2018

1
ただし、そのスキームはJavaが実装するものではありません。Javaはタイプ4 UUIDを実装します。これは純粋にランダムであり、MACアドレスや時間を含みません。ちなみに、現在MACアドレスを選択できる物理デバイスと仮想デバイスが多数あるため、元のアルゴリズムでは一意性が保証されません。
セーレンBoisen

8

回答の多くは、衝突の50%の確率に達するために生成する必要があるUUIDの数について説明しています。しかし、衝突が(実質的に)不可能でなければならないアプリケーションでは、衝突の可能性が50%、25%、または1%でも意味がありません。

プログラマは、発生する可能性のある、また発生する可能性のある他のイベントを日常的に「不可能」として却下しますか?

データをディスクまたはメモリに書き込んで、それを再度読み取る場合、データが正しいことは当然です。破損の検出は、デバイスのエラー修正に依存しています。ただし、未検出のエラーが発生する可能性は、実際には約2 -50です。

ランダムなUUIDに同様の標準を適用することは理にかなっていますか?その場合、約1,000億個のランダムUUIDのコレクション(2 36.5)で「不可能」な衝突が発生する可能性があることがわかります。

これは天文学的な数字ですが、国の医療システムでの項目別請求や、多数のデバイスでの高周波センサーデータのロギングなどのアプリケーションは、これらの制限に確実にぶつかることがあります。次のHitchhiker's Guide to the Galaxyを作成する場合は、各記事にUUIDを割り当てないでください。


比較のポイントとして、パワーボールのジャックポットを獲得するチャンスは3億分の1ですが、1000万から2,000万のチケットの販売が一般的です。重要なのは、多くの人が「不可能」を数億に1回のチャンスよりも小さいものとして定義することです。
エリクソン2018年

4

ほとんどの回答は理論に焦点を当てているので、私が行った実際的なテストを行うことで、議論に何かを追加できると思います。私のデータベースには、Java 8 UUID.randomUUID()を使用して生成された約450万のUUIDがあります。次のものは私が見つけたほんの一部です:

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

本当にランダムな場合は、450万のエントリしか考慮していないため、このような類似のUUIDが存在する可能性はかなり低くなります(編集を参照)。この機能は良好であるもののので、衝突を持っていないという点で、私のためにそれはいないようだということが理論的になりますように良いが。

編集

多くの人がこの答えを理解していないようですので、私のポイントを明確にします。類似点は「小さく」、完全な衝突にはほど遠いことは知っています。ただし、私はJavaのUUID.randomUUID()を実際の乱数ジェネレーターと比較したかっただけです。これは実際の問題です。

真の乱数ジェネレータでは、最後のケースが発生する確率は約0.007%です。したがって、私の結論は正しいと思います。

式は、このwiki記事en.wikipedia.org/wiki/Birthday_problemで説明されています


6
本当じゃない。この種の類似点は、4.5MのUUIDで真の乱数ジェネレータを使用しても発生します。あなたが与えたUUIDの類似点は小さく、はるかに、完全な衝突からは程遠いものです。
user3711864 2017年

類似点は「小さい」ものであり、完全な衝突には程遠いことを私は完全に同意します。ただし、JavaのUUID.randomUUID()を真の乱数ジェネレーターと比較したかっただけです(これが問題です)。一部の計算では、真の乱数ジェネレーターで、最後のケースが発生する確率は約1-e ^(-4500000 ^ 2 /(2 * 36 ^ 11))= 0.007%= 1 13k。私は非常に幸運:)でなければならないであろう
アンドレ・ピニェイロ

1
450万個のアイテムと13分の1の確率で、このような部分的な衝突は346回予想されませんか?
ベン・リー

@BenLeeではありません。450万個のアイテムがあることを考慮して、そのイベントが発生する確率を計算しました。各アイテムが1万3000分の1の確率で発生するわけではありません。私が使用される式は、このwikiの記事で見つけることができますen.wikipedia.org/wiki/Birthday_problem
アンドレ・ピニェイロ

2
あなたの期待は何でしたか?類似は同じではありませんよね?
Koray Tugay

3

去年は宝くじに行って勝ったことがないのですが……。

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

タイプ1:実装されていません。uuidが同時に生成されると、衝突が発生する可能性があります。この問題を回避するために、implを人為的に非同期にすることができます。

タイプ2:実装を見ることはありません。

タイプ3:md5ハッシュ:衝突の可能性(128ビット-2テクニカルバイト)

タイプ4:ランダム:衝突の可能性(宝くじとして)。jdk6 implは「真の」安全なランダムを使用しないことに注意してください。これは、PRNGアルゴリズムが開発者によって選択されず、システムに「悪い」PRNGアルゴを使用させることができるためです。したがって、UUIDは予測可能です。

タイプ5:sha1ハッシュ:実装されていません:衝突の可能性があります(160ビット2テクニカルバイト)


4
宝くじに当たる確率は、おそらく1億から1億分の1(10 ^ 7または10 ^ 8)またはそのようなものです。128ビットの乱数との衝突の確率は、3.4 * 10 ^ 28です。抽選券はいつでもください!
スティーブンC

0

アプリケーションでJavaのランダムUUIDを1年以上使用しており、それを非常に広範囲にわたって使用しています。しかし、衝突に遭遇することは決してありません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.