ULID Generator - Besplatno Stvaranje Jedinstvenih Sortabilnih ID-ova Online
Besplatni alat za generiranje ULID-ova stvara jedinstvene, sortabilne identifikatore trenutno. Generirajte kriptografski sigurne ULID-ove za baze podataka, API-je i distribuirane sustave online.
ULID Generator
Dokumentacija
Što je ULID?
ULID (univerzalno jedinstveni leksikografski sortirajući identifikator) kod je od 26 znakova koji se upotrebljava za označavanje zapisa u bazi podataka ili događaja u distribuiranom sustavu. Kombinira trenutačno vrijeme sa slučajnim podacima pa se popis ULID-ova sortiran abecednim redom na kraju sortira prema vremenu stvaranja svakog od njih. Generator ULID-ova alat je koji proizvodi te kodove.
Struktura ULID-a
ULID ima dva dijela, zapisana jedan za drugim bez razdjelnika:
- Vremenska oznaka (10 znakova): broj milisekundi od 1. siječnja 1970. (Unixove epohe), koji obuhvaća do 48 bitova.
- Slučajni dio (16 znakova): 80 bitova slučajnih podataka, dodanih kako bi dva ULID-a stvorena u istoj milisekundi gotovo sigurno bila različita.
Oba se dijela zapisuju abecedom Crockford Base32: znamenkama 0–9 i slovima A–Z, bez slova I, L, O i U. Ta su četiri slova izostavljena jer ih se može zamijeniti sa znamenkama 0 i 1 ili međusobno. Rezultat je niz koji je kratak, lako se čita naglas i može se sigurno izravno upotrijebiti u URL-u.
Kako izračunati ULID
Generator ULID-a gradi identifikator u tri koraka.
- Očitajte trenutačno vrijeme u milisekundama od Unixove epohe. To je broj od 48 bitova.
- Generirajte 80 bitova slučajnih podataka, obično pomoću kriptografski sigurnog generatora slučajnih brojeva, čime se dobiva 10 slučajnih bajtova.
- Kodirajte oba dijela zasebno pomoću abecede Crockford Base32: vremenska oznaka od 48 bitova postaje 10 znakova, a slučajna vrijednost od 80 bitova postaje 16 znakova. Dva kodirana niza spajaju se u završni ULID od 26 znakova.
Kodiranje funkcionira tako da se broj čita po 5 bitova odjednom jer svaki znak Base32 predstavlja jednu od 32 mogućih vrijednosti (2^5 = 32). Deset znakova sadržava do 50 bitova, što je dovoljno za vremensku oznaku od 48 bitova. Šesnaest znakova sadržava točno 80 bitova, koliko ih ima i slučajni dio, bez preostalih bitova.
Primjer s rješenjem
Pretpostavimo da generator ULID-a radi s vremenskom oznakom 1712345678901 (milisekunde od epohe) i dobiva slučajne bajtove [12, 240, 88, 3, 199, 45, 6, 231, 128, 17].
Korak 1 – kodiranje vremenske oznake. Uzastopno dijelite 1712345678901 s 32, svaki put uzimajući ostatak i čitajući znamenke od posljednje prema prvoj (to je standardno pretvaranje baze). Tako nastaje niz od 10 znakova 01HTQW311N.
Korak 2 – kodiranje slučajnog dijela. Pakirajte 10 slučajnih bajtova u niz od 80 bitova, a zatim čitajte po 5 bitova i pretvarajte svaki blok od 5 bitova u znak Base32. Tako nastaje niz od 16 znakova 1KR5G0Y75M3EF00H.
Korak 3 – spajanje dijelova. Završni ULID glasi:
101HTQW311N 1KR5G0Y75M3EF00H
2bez razmaka: 01HTQW311N1KR5G0Y75M3EF00H, ukupno 26 znakova.
Upotreba ovog generatora
Generator radi u pregledniku. Svaki se ULID sastavlja pomoću sata preglednika i 80 novih slučajnih bitova dobivenih iz kriptografskog generatora slučajnih brojeva preglednika, pa se nijedan identifikator ne šalje poslužitelju niti se s njega dohvaća.
- Broj ULID-ova prihvaća cijeli broj od 1 do 50. Zadana je vrijednost 1.
- Generiraj ULID proizvodi novu skupinu. Promjenom broja također se proizvodi nova skupina.
- Kopiraj uz rezultat kopira taj pojedinačni ULID. Kada je prikazano više ULID-ova, Kopiraj sve kopira cijeli popis, po jedan ULID u retku.
- Poništi vraća broj na 1 i generira jedan novi ULID.
Ispod rezultata ploča Struktura ULID-a dijeli prvi ULID u skupini na njegova dva dijela: prvih 10 znakova (vremensku oznaku) i posljednjih 16 znakova (slučajni dio).
ULID u odnosu na UUID
| Značajka | ULID | UUID (verzija 4) |
|---|---|---|
| Duljina | 26 znakova | 36 znakova (s crticama) |
| Sortiranje prema vremenu stvaranja | Da | Ne |
| Kodiranje | Crockford Base32 | Heksadecimalni sustav |
| Sadržava vremensku oznaku | Da (48 bitova) | Ne |
| Siguran za URL bez izuzimanja znakova | Da | Da |
Oba formata nastoje proizvoditi identifikatore koji su jedinstveni u različitim sustavima bez središnjeg tijela koje dodjeljuje brojeve. Glavna praktična razlika odnosi se na sortiranje: budući da ULID počinje vremenskom oznakom, sortiranje ULID-ova kao običnog teksta također ih sortira prema vremenu. Slučajni UUID nema to svojstvo jer je svaki njegov dio slučajan.
Uobičajene primjene
- Primarni ključevi baze podataka: ULID-ovi omogućuju bazi podataka indeksiranje novih redaka približno redoslijedom njihova umetanja, što mnogi pogoni baza podataka obrađuju učinkovitije nego potpuno slučajne ključeve.
- Distribuirani sustavi: zasebni poslužitelji mogu samostalno generirati ULID-ove bez usklađivanja sa središnjim brojačem, a rezultati su i dalje gotovo sigurno jedinstveni.
- Dnevnici događaja: budući da se ULID-ovi sortiraju prema vremenu, popis ID-ova događaja može poslužiti i kao približna vremenska crta.
- Identifikatori API-ja i datoteka: fiksni format od 26 znakova, siguran za URL, uredno funkcionira u web-adresama i nazivima datoteka.
Povezani formati identifikatora uključuju KSUID, koji također kodira vremensku oznaku radi sortiranja, i Snowflake ID-ove, koje upotrebljavaju Twitter i drugi, a koji kombiniraju vremensku oznaku, identifikator računala i brojač.
Primjeri koda
Svaki primjer u nastavku gradi ULID na isti način kako opisuje specifikacija ULID-a: kodira vremensku oznaku od 48 bitova u 10 znakova Crockford Base32, kodira 80 bitova slučajnosti u još 16 znakova i spaja ih.
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}
41Često postavljana pitanja
Čemu služi ULID? ULID se upotrebljava kao jedinstveni identifikator retka u bazi podataka, resursa API-ja ili zabilježenog događaja u slučajevima kada je korisno i sortiranje prema vremenu stvaranja.
Koliko je dug ULID? ULID uvijek ima 26 znakova: 10 znakova za vremensku oznaku i 16 za slučajni dio.
Koje kodiranje upotrebljava ULID? ULID upotrebljava abecedu Crockford Base32, sastavljenu od znamenki 0–9 i slova A–Z, pri čemu su I, L, O i U uklonjeni kako bi se izbjegla zamjena s drugim znakovima.
Po čemu se ULID razlikuje od UUID-a? ULID se sortira prema vremenu stvaranja i dug je 26 znakova. Slučajni UUID (verzija 4) ne sortira se prema vremenu i dug je 36 znakova, uključujući crtice.
Kolika je vjerojatnost kolizije između dva ULID-a? 80 bitova slučajnosti čini kolizije krajnje malo vjerojatnima. Za vjerojatnost od 50 % da će se bilo koja dva podudarati bilo bi potrebno generirati približno 1,3 bilijuna ULID-ova unutar iste milisekunde.
Mogu li se ULID-ovi generirati bez internetske veze? Da. ULID-u su potrebni samo lokalni sat i generator slučajnih brojeva pa se može izraditi potpuno izvan mreže.
Reference
- "ULID Specification." GitHub, https://github.com/ulid/spec.
- "Crockford's Base32 Encoding." http://www.crockford.com/base32.html.