UUIDのバージョンと使い分け
(ntietz.com)- UUIDにはv1からv8まで8つのバージョンがあり、数字が大きいほど新しい、または優れているという意味ではなく、それぞれ異なる生成方式がRFC 9562で定義されている
- 一般的な選択肢はv4とv7に絞られ、v4はランダムIDのデフォルト、v7は生成時刻順でのソートが必要な場合に適している
- v1とv6は同じ材料を使うが、v6はソートすると生成時刻順になるようフィールドの順序を変更した形式
- v3とv5は入力データをハッシュ化してUUIDを作成し、v3はMD5、v5はSHA-1を使用し、候補となる入力値としてDNSとURLを指定できる
- 可能であればv1・v6の代わりにv7を使い、入力データベースのUUIDが必要ならv5、完全にユーザー定義のUUIDが必要ならv8を検討する、という流れが実用的
UUIDバージョン別の生成方式
- UUIDのバージョンはv1からv8まであり、すべてRFC 9562で定義されている
-
時刻ベースUUID
- UUID Version 1はタイムスタンプ、単調カウンター、MACアドレスから生成される
- UUID Version 6はv1と同じデータを使うが、ソート時に生成時刻順になるよう順序を変更している
- UUID Version 7はタイムスタンプとランダムデータから生成される
-
ランダム・ユーザー定義UUID
- UUID Version 4は完全なランダムデータから生成され、多くの人がUUIDと聞いて思い浮かべる形式に近い
- UUID Version 8は、すべてのバージョンで必要なversion/variantフィールドを除けば、完全にユーザー定義の方式である
-
入力データのハッシュに基づくUUID
- UUID Version 3は、ユーザーが提供したデータのMD5ハッシュから生成される
- RFCの候補入力値にはDNSとURLがある
- UUID Version 5は、ユーザーが提供したデータのSHA-1ハッシュから生成される
- v3と同様に、DNSとURLを入力候補にできる
- UUID Version 3は、ユーザーが提供したデータのMD5ハッシュから生成される
-
予約済みUUID
- UUID Version 2はセキュリティID用に予約されており、既知の詳細情報はない
実際の選定基準
- ほとんどの場合、選択肢はv4またはv7である
- 単にランダムIDが必要なら、v4がデフォルトの選択肢として適している
- IDをソート可能にする必要があるなら、v7を検討できる
- 例として、UUIDをデータベースキーとして使う場合、v7が候補になり得る
- v5またはv8は、UUID内に独自データを入れたい場合に使うものに近い
- この種のものは、たいてい必要な状況をユーザーがすでに把握している場合が多い
- RFCによると、v7はv1とv6を改善するものなので、可能であればv1・v6の代わりにv7を使うべきである
- v1またはv6がどうしても必要なら、v6を使用できる
- v2は特定されていないセキュリティ用途のために予約されている
- v3は、より強いハッシュを使うv5に置き換えられており、v3が必要な場合もユーザーがすでに把握している可能性が高い
1件のコメント
Hacker News の意見
UUID v2 の詳細がないというのは、悪名高いほど不明瞭な RFC だけを読んだ場合の話です: https://pubs.opengroup.org/onlinepubs/9696989899/chap5.htm#t...
ほとんど出会うことはありませんが、version 0 UUID もあります。後に他の「バージョン」が互換性のある形で定義できるようにした予約ビットの出どころなので、触れておく価値があります。関連する調査は自分の UUID ライブラリにまとめてあります: https://github.com/okeeblow/DistorteD/blob/NEW%E2%80%85SENSA...
かっこいいので対応することにしましたが、日付のロールオーバーと、さらに古い Apollo UID の扱い方はまだ決める必要があります
0-7 Variant 空間に定義された歴史的な UUID タイプについては、人々の理解に役立つ情報提供 RFC の作業を始めているところです。議論や文言レビューをしたいなら、https://github.com/yocto/draft-yocto-uuid を見てください
詳細は 2 分で見つけられました。記事のリンクをクリックして RFC 9562 の DCE 定義部分へ行き、その段落の最初のリンクから仕様に入り、「UUID」を検索して付録 A に行けば全部あります
名前は紛らわしく「Universal Unique Identifier」ですが、必要な内容はすべてあります。自分の記事に貼ったリンクくらいは、自分でクリックしてみるとよいでしょう
文脈上、他のバージョンは特定の要素から生成されると説明されているので、その文は明らかに後者を指しています。文が少し不明瞭ではありますが、誤解を誘っているとは言いにくいです
それでも付録は、当時のスナップショットのように読めて面白かったです
73WakrfVbNJBaAmhQtEeDvやbK7nP9xMのような 短い UUID 標準があるとよいですね厳密にはどこかで重複する可能性があるので UUID ではないのでしょうが、ランダムでありながら覚えられる程度に短い ID 標準の組み合わせが欲しいです
もっと人気のある標準がない理由は、何かを諦める必要があるからだと思います。128 ビットならほぼすべての用途で衝突リスクは低いですが、より小さくなるほど具体的な状況と衝突の影響を考慮しなければならず、標準化が難しくなります。base64 や base85 のような別のエンコーディングを使えばもっと短くなりますが、大文字小文字の区別や URL 安全性などを犠牲にすることになります: https://github.com/ulid/spec
同じ UUID の別表現にすぎず、元に戻せます。UUID は結局 128 ビット値なので、実際の変換というより代替表記です
一部の UUID バージョンにある単調ソートの利点は失われますが、base58 は URL セーフで特殊文字を含みません。値は引き続きバイナリとして保存できます。たとえば Postgres では、テキストカラムの代わりに
byteaを使えます議論はこちらで見られます: https://github.com/uuid6/new-uuid-encoding-techniques-ietf-d...
UUID v7 のタイムスタンプは Databend にとって大きな変化でした。AWS S3 でメタデータファイルをタイムスタンプで素早く見つけるために使っているので、vacuum のような処理がずっと速くなりました
PR: https://github.com/datafuselabs/databend/pull/16049
時系列ソート可能な UUID の大きな利点は、局所性がよくなることにあります。インデックスに新しい項目を入れるとき、たいてい末尾に追加する操作になり、ランダム挿入より安くなる可能性があります。ただし競合が増える場合もあるので、タイムスタンプの前に一部のランダムビットを入れて、ソートされた「シャード」を作るハイブリッドも検討に値します。読み取りも最新データに集中することが多いため、最新データが一か所にありキャッシュに乗りやすいのは有用です
uuid2 の目的は理解しにくい。こういうタイプがさらにあることも知らなかったし、Xandr に自分の個人情報削除を依頼したときに初めて uuid2 を見た: https://news.ycombinator.com/item?id=40913915
Wikipedia を読んでも、なぜ「汎用一意識別子」というものを作っておきながら複数のタイプを用意するのか、その一部がもともと PC まで追跡できるように作られていたのか、よく理解できない。MAC コードの一部を混ぜると uuid2 がよりランダムに近くなるのか、それとも別の理由があるのか気になる。プライバシー保護の観点では、選択可能な文字を非常に多くした長い識別子だけを使って、重複の可能性を事実上なくすのではだめなのかも気になる
任意の 2 台のマシンが同じ 2 つの入力に対して同じ UID/UUID を作り、識別されたメッセージを受け取った側は、識別子を元の構成要素に戻すことができた。一時的なメッセージのラベルとして設計されていたため、2 つの次元は時刻とハードウェア ID で、当初は Apollo のシリアル番号、後には Ethernet のハードウェアアドレスなどが使われた
混乱のかなりの部分は、初期の AEGIS 実装で Apollo のエンジニアたちがファイルシステム識別に「canned」、つまり静的でよく知られた UID を使い始めたことに由来すると思う。時間がたつにつれ、UUID の一般的な用途は、重複が意図された一時的な識別子から、重複を避けるべき canned な識別子へと完全に移り、2 つの次元もランダムと、もう一つのランダムになった
歴史はもっと複雑だ。Microsoft は Windows NT 向けの MSRPC を作るために Apollo の中心人物の一人を雇い、そのため GUID も生まれた。GUID はフィールド配置が UUID と異なり、多くの資料が言うのとは違って混合エンディアンではない。Microsoft は一時的な RPC メッセージ識別用 GUID だけでなく、COM クラス、メディアコーデックなど、よく知られた識別子が必要なほぼあらゆるものに canned GUID を好んで使う。例: https://gix.github.io/media-types/
同じコメント欄で自分のリポジトリを 2 回リンクして申し訳ないが、自分の UUID ライブラリの README にこの歴史をまとめ始めていて、また続きを書かなければならない。Apollo は 1980 年に始まり、Leach/Salz の UUID RFC 草案が出たのは 1998 年になってからなので、現代の標準には抜け落ちた話が膨大にある: https://github.com/okeeblow/DistorteD/blob/NEW%E2%80%85SENSA...
UUID v4 は、指定された位置にハイフンを入れる乱数バイト生成器にすぎない。必ず使う必要はなく、自分で乱数バイトを作ればスペースを節約できる
不要なハイフンやバージョン情報のようなものも減らせる
IPv4 アドレスが 32 ビットの数値で、「ドットで区切った 4 つのまとまり」がその表現の一つであるのと似ている。UUID を文字列形式として考えているなら、UUID についての最も基本的な概念から間違っている。単にランダムな識別子が欲しい場合でも、ランダム UUID に「これはランダムであることを意図している」という小さなフラグビットがあるのは良いことだと思う。文脈のない識別子を一つだけ見つけたときに役立つ
複数の生成方式の間に異なる名前空間を作ることが有用かどうかは議論できるが、一般的な乱数生成器が有効な UUIDv4 を作る確率は 1/16 にすぎない。もちろん自分で UUID 生成器を作りたいなら、ビットを正しく設定するのは些細なことだ
Go なら
uuid.New().String()で済むが、crypto/randで乱数データを読み、base64 や hex に変換するには、もっと多くの行数と手間が必要になるMAC ベースのバージョンは使わないことを勧める。理論上は v4 と v7 以外はすべて該当し得るが、v1 が最悪だ
v3 も MD5 がひどく破られているという問題がある
4 番以外の詳細は知らなかったが、本当に有用なのに抜けているのは SHA256 データとカウンターを使う方式のように思える。PBKDF2 に似た形だ
個人情報を保持する派生識別子になり得るし、特定の UUID がどのシードから派生したものかを緩く証明することもできる
それ以外の場合は、もっと長い出力が欲しくなるだろう
単に v7 を使えばよい
ここからセキュリティ専門家たちが「違う」と言う番だ
多くの用途では、データを再処理しても同じ ID を生成できると非常に有用だが、それを実現する標準的な方法は知らない