Pythonでuuid.uuid1()とuuid.uuid4()をいつ使用すればよいですか?


207

私はドキュメントの2つの違いを理解しています。

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

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

したがってuuid1、マシン/シーケンス/時間情報を使用してUUIDを生成します。それぞれの長所と短所は何ですか?

uuid1()はそれがマシン情報に基づいているので、プライバシーの懸念があることを知っています。どちらか一方を選ぶと、もう少し微妙なところがあるのか​​な。uuid4()完全にランダムなUUIDなので、今すぐ使用します。しかしuuid1、衝突のリスクを減らすために使用する必要があるのか​​と思います。

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


3
これは、UUIDの代替アプローチです。衝突の可能性はごくわずかですが、UUIDは一意性を保証するものではありません。一意性を保証するために、複合キーを[<system id>、<local id>]として使用することができます。データ共有に参加する各システムには、システムのセットアップ中に割り当てられるか、IDの共通プールから取得される、システムの固有のIDが必要です。ローカルIDは、特定のシステム内の一意のIDです。これには手間がかかりますが、一意性が保証されます。オフトピックで申し訳ありませんが、助けようとしています。
oᴉɹǝɥɔ

3
彼が言及した「プライバシーの懸念」については対応していません
Shrey

回答:


253

uuid1()衝突が発生しないことが保証されています(同時に多数の衝突を作成しないことを前提としています)。とuuidコンピューターの間に接続がないことが重要である場合は、MACアドレスを使用してコンピューター間で一意にするために使用しません。

100ns未満で2 14を超えるuuid1 を作成することで重複を作成できますが、これはほとんどの使用例では問題になりません。

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

ボブ・アマンによるこの素晴らしい答えはそれをうまくまとめています。(私は答え全体を読むことをお勧めします。)

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


申し訳ありませんが、十分に調査せずにコメントしました-バージョン4のuuidがバージョン1のuuidと衝突しないようにするために予約されているビットがあります。元のコメントを削除します。tools.ietf.org/html/rfc4122を
マークランサム

1
@gsええ、私が読んでいたもので意味があります。uuid1は「よりユニーク」ですが、uuid4はより匿名です。したがって、特に理由がない限り、uuid1を使用してください。@mark ransom:素晴らしい答えです。uuid1/ uuid4を検索しても見つかりませんでした。馬の口からまっすぐに見えます。
rocketmonkeys 2009年

6
uuid1同じノードで毎秒数個を生成する場合、必ずしも一意のUUIDを生成するわけではありません。例:[uuid.uuid1() for i in range(2)]。もちろん、何か奇妙なことが起こっていない限り、私は見逃しています。
Michael Mior 2013年

1
@Michael:uuid1シーケンス番号(例では4番目の要素)があるため、カウンターのすべてのビットを使い果たしない限り、衝突は発生しません。
GeorgSchölly2013年

3
@Michael:衝突が発生する状況を調査して、見つけた情報を追加しました。
GeorgSchölly2013年

32

たとえば、複数のオンライントランザクションがスケーリングのために複数のマシンで処理される場合などUUIDが別々のマシン生成される場合uuid1()uuid4()はなく、検討する1つの例があります。

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

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


20

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

数百台のサーバーをアップグレードしましたが、Amazon EC2インスタンスでこの問題に数回遭遇しました。時計の解像度が悪いのではないかと思い、UUID4に切り替えることで解決しました。


5

uuid1を使用する際の注意点の1つは、デフォルトの呼び出し(clock_seqパラメーターを指定しない)を使用した場合、衝突が発生する可能性があります。ランダム性が14ビットしかない(100ns以内に18のエントリを生成すると、衝突の確率が約1%になる)を参照してください。誕生日のパラドックス/攻撃)。この問題はほとんどの場合で発生することはありませんが、クロックの解像度が低い仮想マシンでは問題が発生します。


7
@Guilaumeは、使用して良い練習の例を見て、本当に有用であろうclock_seq....
エリック・

@Guilaumeこの1%の確率をどのように計算しましたか?ランダム手段の14ビットは、衝突を使用して、100ナノ秒当たりおおよそ163 IDS生じる場合、衝突の1%の確率であることをあなたが> = 2 ^ 14は100nsごとにIDと、この手段を生成する場合に発生することが保証されます
MAKS

1
@maks私が言ったように、あなたは誕生日のパラドックスを見るべきです。
ギヨーム

3

おそらく言及されていないのは、局所性の問題でしょう。

MACアドレスまたは時間ベースの順序付け(UUID1)を使用すると、ランダムに分散されたもの(UUID4)(ここを参照)より数値を並べて並べる作業が少なくなるため、データベースのパフォーマンスが向上します。

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


1

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

ランダムMACを持つv1(「v1mc」)

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

私が最初にこれに遭遇したのは、Postgresのuuid_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オブジェクトを直接作成する、より長いバージョンとより速いバージョンがあります。誰かが望めば投稿できます)


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

import random
from uuid import uuid1

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

この方法はv4(ホストにとらわれない)のように見えますが、より悪い(ビットが少ない、urandomへの依存など)。uuid4だけに比べて利点はありますか?
ロケットサル2017

これは主に、v1が時間ベースの品質に役立つにもかかわらず、より強い衝突抵抗とホストプライバシーが望まれる場合の単なるアップグレードです。1つの例は、データベースの主キーです。v4と比較すると、v1のuuidはディスクへの書き込み時の局所性が向上し、より便利な自然なソートなどが行われます。ただし、攻撃者が2 **と予測するケースがある場合61ビットはセキュリティの問題です(たとえば、uuidがnonceとして)、次に$ dietyはい、代わりにuuid4を使用します(私は知っています!)。再:urandomを使用しているため悪化している、私はあなたが何を意味するのかわからない-Pythonでは、uuid4()もurandomを使用しています。
Eli Collins

良いもの、それは理にかなっています。何ができるか(コード)だけでなく、なぜそれが必要なのかを確認するのは良いことです。再:urandom、つまり、ランダム性の2倍(uuid1に1つ、urandomに1つ)を消費しているため、システムエントロピーをより早く使い切ることができます。
ロケットモンキー2017

実際には、uuid4の約半分です。uuid1()は、clock_seqに14ビットを使用します。これは、2バイトのurandomに切り上げます。uuid1mcラッパーは48ビットを使用します。これは6バイトのurandomにマップする必要があり、呼び出しごとに合計urandom(8)消費されます。一方、uuid4はすべての呼び出しで直接urandom(16)を呼び出します。
Eli Collins
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.