Closed8
[調査] UUID v6 (+v8) はなんなの
導入
- RFC 9562 (2024年5月公開) で UUIDv6, v7, v8 が追加された
- ざっくり調べてるとこれからは v7 が広まりそうみたいなコメントがあったが、じゃあ v6 とv8 はなんなんだよというのが気になったので調べた
(先に簡単な v8 のほうからまとめる)
UUID v8
- カスタム可能なID
- 試験的な実装やベンダーの独自実装で利用されるものであり、最低限のデータフォーマットのみ指定されている。
UUID v6
- UUIDv1 のビットレイアウト(データフォーマット)を入れ替え、IDを時間でソート可能にしたもの
- v1を運用中のシステムで id を v6に置き換える目的で使う
UUID v1
- 時間 + ノード (ID生成器) をベースとしたID。
- 以下のフィールドを含む
- タイムスタンプ(グレゴリオ暦で 1582-10-15T00:00:00Z から100ナノ単位のカウント) (60bits)
- クロックシークエンス(14bits)
- MACアドレス(48bits)
- ノードのMACアドレスを含めることで、ノードごとにユニークな値になることを保証する
- クロックシークエンスはなんらかの理由でクロック(時刻)が進んでいない、または巻戻ったなどの際にIDが重複するのを避けるためのフィールド
- 重複が発生しそうなタイミングでシークエンスを1上げるか、最初からランダムな値をいれてもよい
- ちなみに、 v1 はタイムスタンプの下位32ビットが先頭に置かれるため、時間でソートできなかった
UUIDv1 の懸念事項
- MACアドレスが公開されることでセキュリティ上のリスクが発生する可能性がある
- わかりやすい例では、IDを生成したPCが特定されるなど
- MACアドレスは固定値であり、クロックシークエンスも実装次第では固定値あるいはインクリメンタルな値になるため、IDはある程度類推可能になる。
- タイムスタンプ部分だけ進めていけば総当たりで有効なIDを発見できる
- 「IDが第三者に知られること」が問題になる場合は v1 を利用するのは避けるべき
- 上記の理由でMACアドレスをランダムな値にしてもよいことになっているが、それであれば v1 及び v6 を選択する必要はないように思われる
「IDを時間でソート可能」について
- これは ID に単調性(新しいIDは常に古いIDより値が大きい)を持たせる目的でそうなっている
- IDが単調性を持っていると RDB でインデックスを作成する際、インデックスの書き込み先がランダムにならないので、インデックスの作成効率がよくなるというメリットがある
- なので、作成順でソートするなら
order by id
よりorder by created_at
するほうが望ましいし、uuid をパースしてタイムスタンプを取り出したりはしないほうがよい
UUID v7
- 時間+ランダム値をベースとしたID
- 以下のフィールドを含む
- タイムスタンプ( ミリ秒単位の unix time ) (48bits)
- ランダムa (12bits)
- ランダムb (62bits)
- ランダムa は v1のクロックシークエンスと似たようなフィールドで、バッチ処理で同時に複数のIDを生成する場合に連番をいれたり、ランダムな値を入れたりするフィールド
- 先頭に unix time がそのまま入っているので id が単調増加になる
まとめ
- ID にノードのID を入れたいような特別な事情がなければ v7 でよい
参考文献
おまけ: ulid
ulid は 全体で 128bits なのは uuid と同じで、ミリ秒 unix timestamp (48bits) も uuid v7 と同じだが、 ランダム値が 80 bits で uuid v7 の rand_a と rand_b を足しても 6bit 多い(バージョン・バリアントというメタ情報的なフィールドの分)。ので互換性は無い。
uuid についても単純に文字列表現を短くしたい場合は ulid と同じように Crockford's base32 でエンコードすれば 26文字 になるが、rdb に uuid 型で値を保存するには独自にデコードなど必要。
おまけ(2): 48ビットのミリ秒 unix timestamp
- 西暦10889年まで有効
- 長すぎではという議論はちらほらあったようだが、 8の倍数の方が実装しやすいのとバージョン&バリアントフィールドの位置が決まってるので切り詰めても中途半端な空きになってあまり意味が無いということだと思われる(おそらく)
おまけ(3):base32 エンコード
- UUID の新しいエンコード方法についてもドラフト段階では議論されていたが、途中で範囲外になった模様
(参考)
このスクラップは2024/06/02にクローズされました