Sari la conținut

Generator ULID - Creează Identificatori Unici Sortabili Online Gratuit

Instrument gratuit de generare ULID creează identificatori unici, sortabili instant. Generează ULID-uri criptografic securizate pentru baze de date, API-uri și sisteme distribuite online.

Generator ULID

Introduceți o valoare pentru a vedea rezultatul
Calculator de încărcare...
📚

Documentație

Ce este un ULID?

Un ULID (identificator sortabil lexicografic, universal unic) este un cod de 26 caractere folosit pentru a eticheta înregistrări într-o bază de date sau un eveniment într-un sistem distribuit. Acesta combină ora curentă cu date aleatorii, astfel încât o listă de ULID-uri sortată alfabetic ajunge să fie sortată după momentul creării fiecăruia. Un generator ULID este un instrument care produce aceste coduri.

Structura unui ULID

Un ULID are două părți, scrise una după alta, fără separator:

  • Marcaj temporal (10 de caractere): numărul de milisecunde de la 1 ianuarie 1970 (epoca Unix), reprezentat pe până la 48 de biți.
  • Aleatorietate (16 caractere): 80 de biți de date aleatorii, adăugați pentru ca două ULID-uri create în aceeași milisecundă să fie aproape sigur diferite.

Ambele părți sunt scrise folosind alfabetul Base32 al lui Crockford: cifrele 0–9 și literele A-Z, cu excepția literelor I, L, O și U. Aceste patru litere sunt omise deoarece pot fi confundate cu cifrele 0 și 1 sau între ele. Rezultatul este un șir scurt, ușor de citit cu voce tare și sigur de introdus direct într-un URL.

Cum se calculează un ULID

Un generator ULID construiește un identificator în trei pași.

  1. Se citește ora curentă în milisecunde de la epoca Unix. Acesta este un număr pe 48 de biți.
  2. Se generează 80 de biți de date aleatorii, de obicei cu ajutorul unui generator criptografic sigur de numere aleatorii, rezultând 10 octeți aleatorii.
  3. Se codifică separat ambele părți folosind alfabetul Base32 al lui Crockford: marcajul temporal pe 48 de biți devine 10 caractere, iar valoarea aleatorie pe 80 de biți devine 16 caractere. Cele două șiruri codificate sunt unite pentru a forma ULID-ul final de 26 caractere.

Codificarea funcționează prin citirea numărului câte 5 biți o dată, deoarece fiecare caracter Base32 reprezintă una dintre 32 valori posibile (2^5 = 32). Zece caractere pot conține până la 50 biți, suficient pentru marcajul temporal pe 48 biți. Șaisprezece caractere conțin exact 80 biți, ceea ce corespunde părții aleatorii fără niciun bit rămas.

Exemplu rezolvat

Să presupunem că un generator ULID rulează la marcajul temporal 1712345678901 (milisecunde de la epocă) și extrage octeții aleatorii [12, 240, 88, 3, 199, 45, 6, 231, 128, 17].

Pasul 1 – se codifică marcajul temporal. Se împarte în mod repetat 1712345678901 la 32, păstrând restul de fiecare dată și citind cifrele de la ultima la prima (aceasta este conversia standard între baze). Se obține șirul de 10 caractere 01HTQW311N.

Pasul 2 – se codifică partea aleatorie. Cei 10 octeți aleatorii sunt grupați într-un flux de 80 de biți, apoi sunt citiți câte 5 biți, fiecare grup de 5 biți fiind convertit într-un caracter Base32. Se obține șirul de 16 caractere 1KR5G0Y75M3EF00H.

Pasul 3 – se unesc părțile. ULID-ul final este:

101HTQW311N 1KR5G0Y75M3EF00H
2

scris fără spațiu: 01HTQW311N1KR5G0Y75M3EF00H, cu un total de 26 caractere.

Utilizarea acestui generator

Generatorul rulează în browser. Fiecare ULID este construit folosind ceasul browserului și 80 de biți aleatorii noi preluați de la generatorul criptografic de numere aleatorii al browserului, astfel încât niciun identificator nu este trimis către un server sau preluat de la acesta.

  • Numărul de ULID-uri acceptă un număr întreg de la 1 la 50. Valoarea implicită este 1.
  • Generează ULID produce un lot nou. Schimbarea numărului produce, de asemenea, un lot nou.
  • Copiază de lângă un rezultat copiază acel ULID. Când sunt afișate mai multe, Copiază tot copiază întreaga listă, câte un ULID pe linie.
  • Resetează readuce numărul la 1 și generează un ULID nou.

Sub rezultate, panoul Structura ULID împarte primul ULID din lot în cele două părți ale sale: primele 10 caractere (marcajul temporal) și ultimele 16 (partea aleatorie).

ULID comparat cu UUID

CaracteristicăULIDUUID (versiunea 4)
Lungime26 de caractere36 de caractere (cu cratime)
Sortabil după momentul creăriiDaNu
CodificareBase32 al lui CrockfordHexazecimal
Conține un marcaj temporalDa (48 biți)Nu
Sigur pentru URL fără codificare suplimentarăDaDa

Ambele formate urmăresc să producă identificatori unici între sisteme, fără ca o autoritate centrală să distribuie numere. Principala diferență practică este sortarea: deoarece un ULID începe cu un marcaj temporal, sortarea ULID-urilor ca text simplu le sortează și după timp. Un UUID aleatoriu nu are această proprietate, deoarece fiecare parte a sa este aleatorie.

Utilizări frecvente

  • Chei primare ale bazelor de date: ULID-urile permit unei baze de date să indexeze rândurile noi aproximativ în ordinea în care au fost inserate, lucru pe care multe motoare de baze de date îl gestionează mai eficient decât cheile complet aleatorii.
  • Sisteme distribuite: servere separate pot genera fiecare ULID-uri independent, fără să se coordoneze cu un contor central, iar rezultatele sunt în continuare aproape sigur unice.
  • Jurnale de evenimente: deoarece ULID-urile se sortează după timp, o listă de identificatori de evenimente poate servi și ca o cronologie aproximativă.
  • Identificatori pentru API-uri și fișiere: formatul fix de 26 caractere, sigur pentru URL, funcționează fără probleme în adrese web și nume de fișiere.

Formatele de identificatori asociate includ KSUID, care codifică și un marcaj temporal pentru sortare, și identificatorii Snowflake, utilizați de Twitter și de alții, care combină un marcaj temporal, un identificator al mașinii și un contor.

Exemple de cod

Fiecare exemplu de mai jos construiește un ULID în același mod descris de specificația ULID: codifică marcajul temporal pe 48 de biți ca 10 caractere Base32 Crockford, codifică 80 de biți de aleatoriu ca încă 16 caractere și le unește.

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

Întrebări frecvente

La ce se folosește un ULID? Un ULID este folosit ca identificator unic pentru un rând dintr-o bază de date, o resursă API sau un eveniment înregistrat, în situațiile în care este utilă și sortarea după momentul creării.

Cât de lung este un ULID? Un ULID are întotdeauna 26 caractere: 10 caractere pentru marcajul temporal și 16 pentru partea aleatorie.

Ce codificare folosește un ULID? Un ULID folosește alfabetul Base32 al lui Crockford, alcătuit din cifrele 0–9 și literele A-Z, cu I, L, O și U eliminate pentru a evita confuzia cu alte caractere.

Prin ce diferă un ULID de un UUID? Un ULID se sortează după momentul creării și are 26 caractere. Un UUID aleatoriu (versiunea 4) nu se sortează după timp și are 36 caractere, inclusiv cratime.

Cât de probabilă este o coliziune între două ULID-uri? Cei 80 de biți de aleatoriu fac coliziunile extrem de improbabile. Ar fi necesară generarea a aproximativ 1,3 trilioane de ULID-uri în aceeași milisecundă pentru a ajunge la o probabilitate de 50 % ca oricare două să coincidă.

Pot fi generate ULID-uri fără conexiune la internet? Da. Un ULID are nevoie doar de ceasul local și de un generator de numere aleatorii, astfel încât poate fi creat complet offline.

Referințe

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