web-dev-qa-db-ja.com

Pythonでuuid.uuid1()とuuid.uuid4()をいつ使用する必要がありますか?

docs。 の2つの違いを理解しています

uuid1()
ホストID、シーケンス番号、および現在の時刻からUUIDを生成します

uuid4()
ランダムUUIDを生成します。

したがって、uuid1はmachine/sequence/time infoを使用してUUIDを生成します。それぞれを使用することの長所と短所は何ですか?

uuid1()はマシン情報に基づいているため、プライバシーに関する懸念がある場合があります。どちらかを選択するときに、もう少し微妙な点はないのでしょうか。完全にランダムなUUIDであるため、今はuuid4()を使用しています。しかし、衝突のリスクを減らすためにuuid1を使用すべきかどうか疑問に思います。

基本的に、一方を使用する場合と他方を使用する場合のベストプラクティスに関する人々のヒントを探しています。ありがとう!

193
rocketmonkeys

uuid1()は、衝突を引き起こさないことが保証されています(同時に多くの衝突を作成しないという仮定の下で)。 uuidとコンピューターの間に接続がないことが重要な場合は、MACアドレスがコンピューター全体で一意になるように使用されるため、使用しません。

3つ以上を作成して複製を作成できます14 100ns未満のuuid1ですが、ほとんどのユースケースではこれは問題になりません。

uuid4()は、あなたが言ったように、ランダムなUUIDを生成します。衝突の可能性は、本当に、本当に本当に小さいです。十分に小さいので、心配する必要はありません。問題は、悪い乱数ジェネレーターが衝突を起こしやすくすることです。

Bob Amanによるこの優れた答え はうまくまとめています。 (答え全体を読むことをお勧めします。)

率直に言って、悪意のあるアクターのない単一のアプリケーションスペースでは、衝突が発生するずっと前に、バージョン4 UUIDでさえ、毎秒かなりのUUIDを生成していても、地球上のすべての生命の絶滅が起こります。

240
Georg Schölly

uuid1()ではなくuuid4()を考慮する場合の1つの例は、IDが別々のマシンで生成される場合です。たとえば、複数のオンライントランザクションがスケーリング目的で複数のマシンで処理される場合です。

このような状況では、たとえば、疑似乱数ジェネレーターの初期化方法の選択が不適切であるために衝突が発生するリスクがあり、生成されるUUIDの数が多くなる可能性があるため、重複IDが作成される可能性が高くなります。

uuid1()のもう1つの関心は、各GUIDが最初に作成されたマシンが暗黙的に記録されることです(UUIDの「ノード」部分に)。これと時間情報は、デバッグでのみ役立つ場合があります。

31
mjv

私のチームは、データベースアップグレードスクリプトにUUID1を使用して、数分以内に最大120k個のUUIDを生成するという問題に遭遇しました。 UUIDの衝突により、主キー制約の違反が発生しました。

何百ものサーバーをアップグレードしましたが、Amazon EC2インスタンスでこの問題に何度か遭遇しました。クロックの解像度が低いため、UUID4に切り替えることで解決したと思われます。

15

uuid1を使用する際に注意すべきことは、デフォルトの呼び出しを使用すると(clock_seqパラメーターを指定せずに)衝突が発生する可能性があることです。衝突の約1%の確率で誕生日のパラドックス/攻撃を確認できます)。ほとんどのユースケースでは問題は発生しませんが、クロック解像度が低い仮想マシンでは噛み付きます。

5
Guillaume

おそらく言及されていないものは、地域のそれです。

MACアドレスまたは時間ベースの順序(UUID1)は、ランダムに分散された番号(UUID4)よりも番号を近くに並べ替える作業が少ないため、データベースのパフォーマンスを向上させることができます( here を参照)。

2番目の関連する問題は、Originデータが失われたり、明示的に保存されていない場合でも、UUID1の使用がデバッグに役立つ可能性があることです(これは明らかにOPが言及したプライバシーの問題と矛盾しています)。

3
c z

受け入れられた答えに加えて、いくつかの場合に役立つ3番目のオプションがあります。

ランダムMACを使用するv1(「v1mc」)

ランダムなブロードキャストMACアドレスでv1 UUIDを意図的に生成することにより、v1とv4のハイブリッドを作成できます(これはv1仕様で許可されています)。結果のv1 UUIDは時間に依存します(通常のv1と同様)が、すべてのホスト固有の情報(v4など)がありません。衝突抵抗の点でもv4に非常に近い:v1mc = 60ビットの時間+ 61ランダムビット= 121固有ビット。 v4 = 122ランダムビット。

私が最初に遭遇したのは、Postgresの id_generate_v1mc() 関数です。それ以来、次のpythonに相当するものを使用しました。

from os import urandom
from uuid import uuid1
_int_from_bytes = int.from_bytes  # py3 only

def uuid1mc():
    # NOTE: The constant here is required by the UUIDv1 spec...
    return uuid1(_int_from_bytes(urandom(6), "big") | 0x010000000000)

(注:UUIDオブジェクトを直接作成する、より長く高速なバージョンがあります。必要に応じて投稿できます)


大量のコール/秒の場合、これはシステムのランダム性を使い果たす可能性があります。あなたはcould代わりにstdlib randomモジュールを使用します(おそらくより高速です)。ただし、警告:攻撃者がRNGの状態を判断し、将来のUUIDを部分的に予測できるようになるまでに、数百のUUIDしか必要ありません。

import random
from uuid import uuid1

def uuid1mc_insecure():
    return uuid1(random.getrandbits(48) | 0x010000000000)
1
Eli Collins