ランダム化されたUUIDは、理論的には衝突の可能性が非常に低いことを知っていますが、実際にrandomUUID()
は、衝突がないという点でJava はどれほど優れているのでしょうか。誰かが共有する経験がありますか?
ランダム化されたUUIDは、理論的には衝突の可能性が非常に低いことを知っていますが、実際にrandomUUID()
は、衝突がないという点でJava はどれほど優れているのでしょうか。誰かが共有する経験がありますか?
回答:
UUIDはを使用しますjava.security.SecureRandom
。これは「暗号的に強力」であると想定されています。実際の実装は指定されておらず、JVM間で異なる可能性があります(つまり、作成された具体的なステートメントは1つの特定のJVMに対してのみ有効です)、出力は統計乱数ジェネレータテストに合格する必要があります。
実装がこれを台無しにする微妙なバグを含むことは常に可能ですが(OpenSSHキー生成のバグを参照)、Java UUIDのランダム性について心配する具体的な理由はないと思います。
ウィキペディアには非常に良い答えがあります 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を生成する必要があります。
UUID.randomUUID()
についてであり、与えられた完全な乱数ジェネレーターの理論的な可能性についてではありません。
誰かが共有する経験がありますか?
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の衝突をテストするために必要な時間の長さでは実用的ではないと思います。(仮説的な)巧妙な表現でさえも。
私は専門家ではありませんが、Javaの乱数発生器を長年見てきた賢い人たちだと思います。したがって、ランダムなUUIDが良いと私は思います。したがって、理論的な衝突確率が実際にあるはずです(可能なすべてのUUIDで約1:3×10 ^ 38です。ランダムなUUIDでのみこれがどのように変わるか知っています1/(16*4)
か?上記のものですか?)
私の実際の経験から、これまで衝突は見たことがありません。最初のひげを手にした日には、おそらく驚くほど長いひげが生えたでしょう。
以前の雇用主には、ランダムなuuidを含む一意の列がありました。配備後最初の1週間で衝突が発生しました。確かに、オッズは低いですが、ゼロではありません。そのため、Log4j 2にはUuidUtil.getTimeBasedUuidが含まれています。単一のサーバーで10,000を超えるUUID /ミリ秒を生成しない限り、8,925年間一意のUUIDが生成されます。
UUIDの元の生成方式は、UUIDバージョンを、UUIDを生成しているコンピューターのMACアドレスと、西洋でのグレゴリオ暦の採用以来の100ナノ秒間隔の数と連結することでした。空間(コンピュータ)と時間(間隔の数)の単一の点を表すことにより、値の衝突の可能性は事実上ゼロになります。
回答の多くは、衝突の50%の確率に達するために生成する必要があるUUIDの数について説明しています。しかし、衝突が(実質的に)不可能でなければならないアプリケーションでは、衝突の可能性が50%、25%、または1%でも意味がありません。
プログラマは、発生する可能性のある、また発生する可能性のある他のイベントを日常的に「不可能」として却下しますか?
データをディスクまたはメモリに書き込んで、それを再度読み取る場合、データが正しいことは当然です。破損の検出は、デバイスのエラー修正に依存しています。ただし、未検出のエラーが発生する可能性は、実際には約2 -50です。
ランダムなUUIDに同様の標準を適用することは理にかなっていますか?その場合、約1,000億個のランダムUUIDのコレクション(2 36.5)で「不可能」な衝突が発生する可能性があることがわかります。
これは天文学的な数字ですが、国の医療システムでの項目別請求や、多数のデバイスでの高周波センサーデータのロギングなどのアプリケーションは、これらの制限に確実にぶつかることがあります。次のHitchhiker's Guide to the Galaxyを作成する場合は、各記事にUUIDを割り当てないでください。
ほとんどの回答は理論に焦点を当てているので、私が行った実際的なテストを行うことで、議論に何かを追加できると思います。私のデータベースには、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で説明されています
去年は宝くじに行って勝ったことがないのですが……。
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テクニカルバイト)