Preskoči na sadržaj

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

Unesite vrijednost za prikaz rezultata
Kalkulator učitavanja...
📚

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.

  1. Očitajte trenutačno vrijeme u milisekundama od Unixove epohe. To je broj od 48 bitova.
  2. Generirajte 80 bitova slučajnih podataka, obično pomoću kriptografski sigurnog generatora slučajnih brojeva, čime se dobiva 10 slučajnih bajtova.
  3. 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
2

bez 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čajkaULIDUUID (verzija 4)
Duljina26 znakova36 znakova (s crticama)
Sortiranje prema vremenu stvaranjaDaNe
KodiranjeCrockford Base32Heksadecimalni sustav
Sadržava vremensku oznakuDa (48 bitova)Ne
Siguran za URL bez izuzimanja znakovaDaDa

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());
33

Python

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())
32

Java

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

  1. "ULID Specification." GitHub, https://github.com/ulid/spec.
  2. "Crockford's Base32 Encoding." http://www.crockford.com/base32.html.