UUID v4 / UUID v7 / ULID alapos összehasonlítása: hogyan válasszunk időrend, hatékonyság és olvashatóság alapján
Az UUID és az ULID olyan azonosító-generáló megoldások, amelyek elosztott rendszerekben vagy adatbázisokban biztosítják az egyediség követelményét. A formátumuk első pillantásra hasonlónak tűnik, ám a szabványosítás, a tárolási hatékonyság, az emberi olvashatóság és az információszivárgási kockázat tekintetében jelentős különbségek vannak. Az alábbiakban a három legfontosabb megközelítést – UUID v4, UUID v7, ULID – rendszerezzük, majd a végén kiegészítésként kitérünk a UUID v1 / v6 változatokra is.
Az azonosítók generálására és az időbélyegek visszafejtésére szolgáló, böngészőben futó (teljesen kliensoldali) eszközök itt érhetők el:
UUID v4: teljesen véletlenszerű forma
Az UUID v4 a 128 bitből 122 bitet tiszta véletlenszámra fordít, így az ütközés valószínűsége rendkívül alacsony. Ennek ára, hogy nem sorbarendezhető időrend szerint, ezért B-Tree alapú indexekben gyakori lapfelosztást eredményez, romolhat a beszúrási lokalitás. Olyan esetekben ideális, ahol a „teljes véletlen” elegendő, például munkamenet-azonosítók vagy egyszer használatos kulcsok.
UUID v7: a kronológiailag rendezhető evolúció
A 2024-ben RFC 9562-ben szabványosított UUID v7 az első 48 bitben UNIX-epoch időt (milliszekundum) tárol, a többi bitet véletlen tölti ki. A lexikografikus (sztring) sorrend megegyezik a generálási sorrenddel, vagyis főkulcsként is megőrzi az indexek lokális jellegét. Az is előny, hogy változtatás nélkül tárolható a meglévő uuid
típusú vagy BINARY(16)
mezőkben.
- Véletlen bitek hossza: a v7 a version/variant bitek kivételével nagyjából 74 bitnyi véletlen értéket használ. Egyes implementációk monotonikus generálással (azonos milliszekundumon belüli ütközések megelőzése) a véletlen bitek egy részét újrakalibrálják, de a statisztikai véletlenszerűség így is bőséges.
- Információszivárgási kockázat: az azonosítóból visszakövethető a generálási idő (ms pontossággal). Ha nagy a kibocsátás és gyenge a véletlengenerátor, akkor könnyebb lehet a közeli azonosítók megtippelése. Belső rendszerekben ez többnyire vállalható, nyilvános végpontoknál azonban oda kell figyelni.
ULID: emberközeli azonosító
A 2016-ban ismertetett ULID egy de facto szabvány, amely Crockford-féle Base32 26 karakteres ábrázolását használja. Kihagyja a könnyen összetéveszthető karaktereket (O/I/L/1), ezért jól illeszthető URL-be és könnyű másolni. Az UUID v7-hez hasonlóan az első 48 bit az idő (ms), így a karakterláncok lexikografikus sorrendje az időrendet követi.
- Rendezhetőség: a ULID-ok Base32 karakterláncainak lexikografikus összehasonlítása mindig időrendi sorrendet ad (a monotonikus generálás széles körben alkalmazott).
- Tárolási forma:
TEXT(26)
mezőben könnyű olvasni, viszont bináris tároláshoz Base32↔16 bájt átalakítás kell. Bár 128 bites binárisként kezelhető, sok RDBMS UUID-specifikus típusaival nem kompatibilis. - Információszivárgási kockázat: a v7-hez hasonlóan itt is látható az idő (ms). Ha nem szeretnénk, hogy a nyilvános API-k erőforrás-azonosítóiból kikövetkeztessék a kiadási sorrendet, körültekintően kell dönteni.
A három megközelítés összehasonlítása (gyakorlati nézőpontból)
Tétel | UUID v4 | UUID v7 | ULID |
---|---|---|---|
Szabvány | RFC 4122 | RFC 9562 (2024) | Nem hivatalos (de facto) |
Bitfelépítés | 128 bitből 122 bit véletlen | 48 bit = UNIX ms + maradék véletlen (monotonikus lehetséges) |
48 bit = UNIX ms + 80 bit véletlen |
Véletlen entrópia | ≈122 bit | ≈74 bit (version/variant levonása után) | 80 bit |
Karakteres ábrázolás | 36 karakter (hex + kötőjel) | 36 karakter (hex + kötőjel) | 26 karakter (Crockford Base32) |
Természetes rendezés (szöveg) | × (véletlen) | ○ (lexikografikus = időrend) | ○ (lexikografikus = időrend) |
Természetes rendezés (bináris) | × | ○ (BINARY(16) összehasonlítás növekvő) |
○ (ha a 6 bájtos időt nagy végű sorrendben tároljuk, memcmp szerint növekvő) |
Adatbázis-tárolás | uuid típus / BINARY(16) ideális |
uuid típus / BINARY(16) ideális |
TEXT(26) olvasható, BINARY(16) -hoz konverzió kell / UUID típushoz gyakran nem kompatibilis |
Indexlokalitás | Gyenge (véletlen beszúrás szétszedi) | Jó (sorrendezett beszúrás / hotspotokra figyeljünk) | Jó (sorrendezett beszúrás / hotspotokra figyeljünk) |
Egyenlőségi keresés költsége | Alacsony (16 bájt összevetés) | Alacsony (16 bájt összevetés) | Szövegként kissé magasabb (összehasonlítás), binárisan alacsony |
Kódolási teher | Hex↔16 bájt (könnyű) | Hex↔16 bájt (könnyű) | Base32↔16 bájt (kissé nehezebb) |
Olvashatóság / URL-kompatibilitás | Alacsony | Alacsony | Magas |
Információszivárgás (időbélyeg) | Nincs | Van (ms) | Van (ms) |
Jellemző felhasználás | Munkamenet-ID, egyszer használatos kulcs | Adatbázis főkulcs, eseményazonosító, idősoros napló | URL-ek, publikus ID, naplók olvashatósága |
Kiegészítés (v7/ULID hotspotok): ha egyetlen shardra vagy elsődleges replikára koncentrált végű beszúrás történik, a B-Tree utolsó szintje könnyen forró ponttá válik. Enyhítésre alkalmazhatunk kis mértékű felső-bites keverést („prefix shuffle”) vagy shard kulcsokat.
Adatbázis-megjegyzések (PostgreSQL / MySQL / SQLite)
- PostgreSQL
- v4/v7: a
uuid
típus a legjobb. A v7 lexikografikus rendezése is érvényesül, ha sztringbőluuid
-vá alakítjuk. - ULID:
char(26)
/text
mezőben vagybytea(16)
-ként (Base32-konverzióval) használható.
- v4/v7: a
- MySQL/InnoDB
BINARY(16)
gyors és takarékos (v4/v7). A v7 big-endian sorrendben természetes rendezést biztosít. ULID-hozCHAR(26)
vagyBINARY(16)
+ konverzió kell.
- SQLite
- Nincs dedikált UUID típus.
BLOB(16)
vagyTEXT
formában kezeljük. Indexelt BLOB esetén is megfelelő a teljesítmény.
- Nincs dedikált UUID típus.
Biztonsági szempontok
- Megjósolhatóság: a v7/ULID azonos milliszekundumban közös időbiteket használ, így ha a véletlenszám-generálás gyenge és nagy a kibocsátási sebesség, nő a közeli ID-k becslésének kockázata. Használjunk kriptográfiai biztonságú PRNG-t, és minimalizáljuk a monotonikus növelésből fakadó mintákat.
- Metadat-szivárgás: az azonosítókból kiolvasható a generálási idő és nagyjából a mennyiség. Publikus API-kon célszerű belső és külső azonosítókat szétválasztani.
Összegzés: hogyan válasszunk?
- UUID v4: teljesen véletlenszerű, nincs rendezhetőség. Elméletileg minimális ütközési kockázat marad. Munkamenetekhez, CSRF tokenekhez illik.
- UUID v7: szabványos, rendezhető UUID. Belső rendszerekben, adatbázis főkulcsként optimális. A monotonikus generálás a gyakorlatban kiküszöböli az ütközést.
- ULID: (a másik kettőhöz képest) emberbarátabb. Ha az olvashatóság vagy URL-kompatibilitás fontos, erős jelölt, de belső főkulcsnak sokszor a v7 célszerűbb. A monotonikus generálás itt is gyakorlatilag elkerüli az ütközést.
Kiegészítés: UUID v1 / v6 röviden
-
UUID v1 (időalap + MAC) 60 bites időbélyeget (100 ns felbontással) és csomópont-azonosítót (gyakran MAC-címet) tartalmaz. Kiváló időrendiség, de a MAC-ből származó hosztinformáció kiszivárgása és a visszaugró óra kezelése problémás. A modern gyakorlatban adatvédelmi okokból többnyire nem ajánlott.
-
UUID v6 (a v1 átrendezett változata) A v1 időbélyege big-endian sorrendbe rendezve a lexikografikus rendezhetőséget javítja. Történetileg „könnyen sorba rakható v1” néven futott, de a szabványosítás végül a v7-re konvergált. Új rendszerekben általában a v6 helyett a v7 a javasolt.
Melléklet: megvalósítási ellenőrzőlista
- Használjunk kriptográfiai PRNG-t (OS által biztosított biztonságos forrás).
- A v7/ULID monotonikus generálás azonos milliszekundumon belül kerülje el az ütközést, miközben minimalizálja a véletlen torzulását.
- Az adatbázisban részesítsük előnyben a
uuid
/BINARY(16)
tárolást, kerüljük a szövegmezők kollációjából adódó teljesítményromlást. - Döntsük el az externális ID-k politikáját (szabad-e az időrend látszódjon). Szükség esetén válasszuk szét a belső és külső azonosítókat.
Összegzésként: a jelenlegi technikai helyzetben belső főkulcsnak a UUID v7 az első számú jelölt, míg ha a használhatóság vagy a megkötések miatt fontos a jobb olvashatóság, akkor az ULID is komoly opció. Csak speciális igény (például szigorú időbélyeg-elrejtés) esetén indokolt a v4 vagy más módszer választása.