ULID Generátor - Egyedi Rendszerezhető Azonosítók Online Ingyenesen
Ingyenes ULID generátor eszköz, amely azonnal létrehoz egyedi, rendszerezhető azonosítókat. Generáljon kriptográfiailag biztonságos ULID-okat adatbázisokhoz, API-khoz és elosztott rendszerekhez online.
ULID Generátor
Dokumentáció
Mi az a ULID?
A ULID (Universally Unique Lexicographically Sortable Identifier, azaz univerzálisan egyedi, lexikográfiailag rendezhető azonosító) egy 26 karakterből álló kód, amely adatbázisbeli rekordok vagy elosztott rendszerbeli események azonosítására szolgál. Az aktuális időt véletlenszerű adatokkal kombinálja, ezért az ábécésorrendbe rendezett ULID-lista végül az egyes azonosítók létrehozási ideje szerint is rendezett lesz. A ULID-generátor ezeket a kódokat előállító eszköz.
A ULID felépítése
A ULID két, egymás után, elválasztójel nélkül leírt részből áll:
- Időbélyeg (10 karakter): az 1970. január 1. óta eltelt ezredmásodpercek száma (a Unix-epocha), legfeljebb 48 biten.
- Véletlenszerű rész (16 karakter): 80 bitnyi véletlenszerű adat, amely biztosítja, hogy az ugyanazon ezredmásodpercben létrehozott két ULID szinte biztosan különböző legyen.
Mindkét részt a Crockford-féle Base32 ábécé használatával írják: a 0–9 számjegyekkel és az A–Z betűkkel, az I, L, O és U betűk kivételével. Ezt a négy betűt azért hagyják ki, mert összetéveszthetők a 0 és 1 számjegyekkel, illetve egymással. Az eredmény rövid, könnyen felolvasható karakterlánc, amely közvetlenül URL-be is beilleszthető.
Hogyan számítható ki egy ULID?
A ULID-generátor három lépésben állítja elő az azonosítót.
- Az aktuális idő beolvasása ezredmásodpercben a Unix-epoch óta. Ez egy 48 bites szám.
- 80 bitnyi véletlenszerű adat előállítása, általában kriptográfiailag biztonságos véletlenszám-generátorból, ami 10 véletlenszerű bájtot ad.
- A két rész külön kódolása a Crockford-féle Base32 ábécé használatával: a 48 bites időbélyegből 10 karakter, a 80 bites véletlenszerű értékből pedig 16 karakter lesz. A két kódolt karakterláncot összefűzve kapjuk a végső, 26 karakteres ULID-et.
A kódolás során a számot egyszerre 5 bitenként olvassák, mivel minden Base32-karakter a 32 lehetséges érték egyikét jelöli (2^5 = 32). Tíz karakter legfeljebb 50 bitet tárol, ami elegendő a 48 bites időbélyeghez. Tizenhat karakter pontosan 80 bitet tárol, így a véletlenszerű rész maradék nélkül illeszkedik.
Kidolgozott példa
Tegyük fel, hogy egy ULID-generátor a 1712345678901 időbélyegnél fut (az epoch óta eltelt ezredmásodpercekben), és a következő véletlenszerű bájtokat generálja: [12, 240, 88, 3, 199, 45, 6, 231, 128, 17].
1. lépés – az időbélyeg kódolása. A 1712345678901 értéket ismételten elosztjuk 32-vel, minden alkalommal feljegyezve a maradékot, majd a számjegyeket az utolsótól az elsőig olvassuk (ez a szokásos számrendszer-alakítás). Ebből a következő, 10 karakteres karakterlánc lesz: 01HTQW311N.
2. lépés – a véletlenszerű rész kódolása. A 10 véletlenszerű bájtot 80 bites adatfolyamba rendezzük, majd egyszerre 5 bitet olvasunk ki, és minden 5 bites részt Base32-karakterré alakítunk. Ebből a következő, 16 karakteres karakterlánc lesz: 1KR5G0Y75M3EF00H.
3. lépés – a részek összefűzése. A végső ULID:
101HTQW311N 1KR5G0Y75M3EF00H
2szóköz nélkül írva: 01HTQW311N1KR5G0Y75M3EF00H, összesen 26 karakter.
A generátor használata
A generátor a böngészőben fut. Minden ULID a böngésző órája és a böngésző kriptográfiai véletlenszám-generátorából származó 80 friss véletlenszerű bit alapján készül, ezért egyetlen azonosítót sem küld a rendszer szerverre, és nem is kér le onnan.
- ULID-ek száma: 1 és 50 közötti egész szám adható meg. Az alapértelmezett érték 1.
- ULID generálása: új köteget állít elő. A darabszám módosítása szintén új köteget hoz létre.
- Az eredmény mellett található Másolás az adott ULID-et másolja. Ha egynél több ULID látható, a Mindet másolja a teljes listát másolja, soronként egy ULID-del.
- A Visszaállítás a darabszámot 1 értékre állítja, és egy új ULID-et generál.
Az eredmények alatt található ULID-struktúra panel a köteg első ULID-jét két részre bontja: az első 10 karakterre (az időbélyegre) és az utolsó 16 karakterre (a véletlenszerű részre).
ULID és UUID összehasonlítása
| Jellemző | ULID | UUID (4-es verzió) |
|---|---|---|
| Hossz | 26 karakter | 36 karakter (kötőjelekkel) |
| Létrehozási idő szerint rendezhető | Igen | Nem |
| Kódolás | Crockford-féle Base32 | Hexadecimális |
| Időbélyeget tartalmaz | Igen (48 bit) | Nem |
| Escape-elés nélkül biztonságosan használható URL-ben | Igen | Igen |
Mindkét formátum célja olyan azonosítók előállítása, amelyek központi hatóság által kiosztott számozás nélkül is egyediek maradnak a rendszerek között. A fő gyakorlati különbség a rendezés: mivel a ULID időbélyeggel kezdődik, az egyszerű szövegként rendezett ULID-ek időrendben is rendezettek lesznek. Egy véletlenszerű UUID-re ez nem igaz, mivel minden része véletlenszerű.
Gyakori alkalmazások
- Adatbázis elsődleges kulcsai: a ULID-ek lehetővé teszik, hogy az adatbázis az új sorokat nagyjából a beszúrásuk sorrendjében indexelje, amit sok adatbázismotor hatékonyabban kezel, mint a teljesen véletlenszerű kulcsokat.
- Elosztott rendszerek: a különálló szerverek egymástól függetlenül, központi számlálóval való egyeztetés nélkül is generálhatnak ULID-eket, és az eredmények így is szinte biztosan egyediek lesznek.
- Eseménynaplók: mivel a ULID-ek időrendben rendezhetők, az eseményazonosítók listája hozzávetőleges idővonalként is használható.
- API- és fájlazonosítók: a rögzített, 26 karakteres, URL-ben biztonságosan használható formátum jól működik webcímekben és fájlnevekben.
Kapcsolódó azonosítóformátum a KSUID, amely szintén időbélyeget kódol a rendezéshez, valamint a Twitter és mások által használt Snowflake-azonosítók, amelyek időbélyeget, gépazonosítót és számlálót kombinálnak.
Kódpéldák
Az alábbi példák mind ugyanúgy építenek fel egy ULID-et, ahogyan azt a ULID-specifikáció leírja: a 48 bites időbélyeget 10 Crockford-féle Base32-karakterként kódolják, 80 bitnyi véletlenszerű adatot további 16 karakterként kódolnak, majd összefűzik őket.
JavaScript
1const ENCODING_CHARS = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';
2
3function encodeULID(time, randomBytes) {
4 // Timestamp: 48 bits -> 10 characters
5 let timestampStr = '';
6 let t = time;
7 for (let i = 0; i < 10; i++) {
8 timestampStr = ENCODING_CHARS[t % 32] + timestampStr;
9 t = Math.floor(t / 32);
10 }
11
12 // Randomness: 80 bits -> 16 characters
13 let result = timestampStr;
14 let bits = 0;
15 let bitCount = 0;
16 for (let i = 0; i < 10; i++) {
17 bits = (bits << 8) | randomBytes[i];
18 bitCount += 8;
19 while (bitCount >= 5) {
20 bitCount -= 5;
21 result += ENCODING_CHARS[(bits >> bitCount) & 0x1f];
22 }
23 }
24 return result;
25}
26
27function generateULID() {
28 const randomBytes = crypto.getRandomValues(new Uint8Array(10));
29 return encodeULID(Date.now(), randomBytes);
30}
31
32console.log(generateULID());
33Python
1import os
2import time
3
4ENCODING_CHARS = "0123456789ABCDEFGHJKMNPQRSTVWXYZ"
5
6def encode_ulid(time_ms, random_bytes):
7 # Timestamp: 48 bits -> 10 characters
8 chars = []
9 t = time_ms
10 for _ in range(10):
11 chars.append(ENCODING_CHARS[t % 32])
12 t //= 32
13 timestamp_part = "".join(reversed(chars))
14
15 # Randomness: 80 bits -> 16 characters
16 bits = 0
17 bit_count = 0
18 random_part = []
19 for byte in random_bytes:
20 bits = (bits << 8) | byte
21 bit_count += 8
22 while bit_count >= 5:
23 bit_count -= 5
24 random_part.append(ENCODING_CHARS[(bits >> bit_count) & 0x1F])
25
26 return timestamp_part + "".join(random_part)
27
28def generate_ulid():
29 return encode_ulid(int(time.time() * 1000), os.urandom(10))
30
31print(generate_ulid())
32Java
1import java.security.SecureRandom;
2import java.time.Instant;
3
4public class ULIDGenerator {
5 private static final SecureRandom random = new SecureRandom();
6 private static final char[] ENCODING_CHARS =
7 "0123456789ABCDEFGHJKMNPQRSTVWXYZ".toCharArray();
8
9 public static String generateULID() {
10 long timestamp = Instant.now().toEpochMilli();
11 byte[] randomBytes = new byte[10];
12 random.nextBytes(randomBytes);
13
14 // Timestamp: 48 bits -> 10 characters
15 char[] timestampChars = new char[10];
16 long t = timestamp;
17 for (int i = 9; i >= 0; i--) {
18 timestampChars[i] = ENCODING_CHARS[(int) (t % 32)];
19 t /= 32;
20 }
21
22 // Randomness: 80 bits -> 16 characters
23 StringBuilder result = new StringBuilder(new String(timestampChars));
24 long bits = 0;
25 int bitCount = 0;
26 for (byte b : randomBytes) {
27 bits = (bits << 8) | (b & 0xFF);
28 bitCount += 8;
29 while (bitCount >= 5) {
30 bitCount -= 5;
31 result.append(ENCODING_CHARS[(int) ((bits >> bitCount) & 0x1F)]);
32 }
33 }
34 return result.toString();
35 }
36
37 public static void main(String[] args) {
38 System.out.println(generateULID());
39 }
40}
41Gyakran ismételt kérdések
Mire használható egy ULID? A ULID adatbázissor, API-erőforrás vagy naplózott esemény egyedi azonosítójaként használható olyan esetekben, amikor a létrehozási idő szerinti rendezés is hasznos.
Milyen hosszú egy ULID? A ULID mindig 26 karakter hosszú: 10 karakter az időbélyeg, 16 pedig a véletlenszerű rész.
Milyen kódolást használ a ULID? A ULID a Crockford-féle Base32 ábécét használja, amely a 0–9 számjegyekből és az A–Z betűkből áll, az I, L, O és U betűk nélkül, hogy elkerülje a más karakterekkel való összetévesztést.
Miben különbözik a ULID a UUID-től? A ULID a létrehozási idő szerint rendezhető, és 26 karakter hosszú. Egy véletlenszerű (4-es verziójú) UUID nem rendezhető idő szerint, és kötőjelekkel együtt 36 karakter hosszú.
Mekkora a két ULID ütközésének valószínűsége? A 80 bitnyi véletlenszerűség miatt az ütközések rendkívül valószínűtlenek. Körülbelül 1,3 billió, ugyanazon ezredmásodpercen belül generált ULID-re lenne szükség ahhoz, hogy két azonos ULID előfordulásának esélye elérje az 50%-ot.
Generálhatók ULID-ek internetkapcsolat nélkül? Igen. A ULID-hez csak a helyi óra és egy véletlenszám-generátor szükséges, így teljesen offline is létrehozható.
Hivatkozások
- "ULID Specification." GitHub, https://github.com/ulid/spec.
- "Crockford's Base32 Encoding." http://www.crockford.com/base32.html.