web-dev-qa-db-ja.com

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

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

287
Alvin

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

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

154

ウィキペディアには非常に良い答えがあります 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を生成する必要があります。

107
sheki

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

タイプ4のUUIDには2^122の可能な値があります。 (この仕様では、型については2ビット、バージョン番号についてはさらに4ビットを失うことになっています。)

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

誰かが実際の生活の中で複製を経験した(すなわち実際に気付いた)可能性は、衝突を探すのが実際上困難であるために、消えるほど小さいよりもさらに小さい。

もちろん、真の乱数の発生源ではなく、通常は擬似乱数発生器を使用します。しかし、あなたがあなたの暗号強度乱数に信用できるプロバイダを使っているならば、それは意志暗号強度であり、繰り返しの可能性は、理想的な(偏りのない)乱数ジェネレータ。

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


1 - あなたが匿名のコメント投稿者によって提案されたような "ある種のバイナリBツリー"を使ったと仮定すると、それぞれのUUIDはN個の異なるUUIDを表すためにO(NlogN)ビットのRAMメモリを必要とします。ビットこれに1,000,000と実験を実行する秒数を掛けます。高品質のRNGの衝突をテストするのに必要な時間の長さのためにそれが実用的ではないと思います。 (仮説的な)巧妙な表現でさえありません。

66
Stephen C

私は専門家ではありませんが、何年もの間、十分な賢明な人々がJavaの乱数ジェネレータを見ていたと思います。したがって、ランダムなUUIDが適切であると仮定します。したがって、実際の理論上の衝突確率(約1: ×10 ^ 38 をすべての可能なUUIDに対して持つ必要があります。ランダムUUIDについてのみこれがどのように変化するかを知っていますか?1/(16*4)上記の?)

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

20
sfussenegger

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

10
Alex2Ustas

以前の雇用主では、ランダムUUIDを含むユニークなコラムがありました。展開されてから1週間後に衝突が発生しました。確かに、オッズは低いですが、ゼロではありません。それがLog4j 2がUuidUtil.getTimeBasedUuidを含む理由です。単一のサーバーで1ミリ秒あたり10,000以上のUUIDを生成しない限り、8,925年間固有のUUIDが生成されます。

7
rgoers

回答の多くは、衝突の可能性が50%に達するためにいくつのUUIDを生成する必要があるのか​​を説明しています。しかし、衝突が(事実上)不可能でなければならないアプリケーションでは、50%、25%、さらには1%の衝突の可能性は無意味です。

プログラマーは日常的に起こり得る他の出来事を「不可能な」ものとして棄却しますか。

データをディスクまたはメモリに書き込み、それをもう一度読み返すと、データが正しいことは当然のことと考えられます。破損を検出するには、デバイスのエラー修正を利用します。しかし、検出されないエラーの可能性は実際にはおよそ2-50

ランダムなUUIDに同様の標準を適用することは意味がありませんか?そうすると、約1000億のランダムUUIDの集まりで「不可能な」衝突が起こり得ることがわかります(236.5).

これは天文学的な数字ですが、国民医療システムでの明細請求、または多数のデバイスへの高周波センサーデータのロギングなどのアプリケーションは、間違いなくこれらの制限にぶつかる可能性があります。もしあなたが次の記事を書いているのであればヒッチハイクの銀河ガイドそれぞれの記事にUUIDを割り当てようとしないでください!

6
erickson

私は昨年の宝くじでプレーし、そして私は勝ったことがない.... ....それは宝くじが勝者を持っているようだ...

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

タイプ1:実装されていません。 UUIDが同時に生成された場合、衝突が発生する可能性があります。この問題を回避するために、implは人工的にa-synchronizeにすることができます。

タイプ2:実装を見たことがない.

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

タイプ4:ランダム:衝突可能(宝くじとして)。 PRNGアルゴリズムは開発者が選択したものではなく、システムに "poor" PRNGアルゴを使用させることができるため、jdk6は「真の」安全な乱数を使用しないでください。だからあなたのUUIDは予測可能です。

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

4
Giher

私は専門家ではありませんが、誰もが理論について話しているので、実際的な例を示すことによって議論に何かを追加できると思います。私のデータベースには、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-0ba00060fe64"

"be87a209-2114-45b3-9d5a-86d00060fe64"


"4a8a74a6-e972-4069-b480-bdea1177b21f"

"12fb4958-bee2-4c89-8cf8-edea1177b21f"

それが本当に無作為であったならば、私たちは450万のエントリーしか検討していないので、この種の類似したUUIDを持つ可能性はかなり低いでしょう。だから、この機能はいいのですが、衝突がないという点では、私には見えません それ それは理論的にはそうであるように良いです。

3
André Pinheiro

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

1
Afsar