Pereiti prie turinio

ULID generatorius - Kurkite unikalius rūšiuojamus ID internete nemokamai

Nemokamas ULID generatoriaus įrankis akimirksniu sukuria unikalius, rūšiuojamus identifikatorius. Generuokite kriptografiškai saugius ULID identifikatorius duomenų bazėms, API ir paskirstytoms sistemoms internete.

ULID Generatorius

Įveskite reikšmę, kad pamatytumėte rezultatus
Įkrovimo skaičiuotuvas...
📚

Dokumentacija

Kas yra ULID?

ULID (visuotinai unikalus leksikografiškai rikiuojamas identifikatorius) yra 26 simbolių kodas, naudojamas duomenų bazės įrašams arba įvykiui paskirstytoje sistemoje žymėti. Jis sujungia dabartinį laiką su atsitiktiniais duomenimis, todėl abėcėlės tvarka surikiuotas ULID sąrašas galiausiai būna surikiuotas pagal kiekvieno identifikatoriaus sukūrimo laiką. ULID generatorius yra įrankis, sukuriantis šiuos kodus.

ULID struktūra

ULID sudarytas iš dviejų dalių, užrašomų viena po kitos be skirtuko:

  • Laiko žyma (10 simbolių): milisekundžių skaičius nuo 1970 m. sausio 1 d. (Unix epochos pradžios), užimantis iki 48 bitų.
  • Atsitiktinumas (16 simbolių): 80 bitų atsitiktinių duomenų, pridedamų tam, kad du tą pačią milisekundę sukurti ULID beveik neabejotinai skirtųsi.

Abi dalys užrašomos naudojant Crockfordo Base32 abėcėlę: skaitmenis 0–9 ir raides A–Z, išskyrus I, L, O ir U. Šios keturios raidės praleidžiamos, nes jas galima supainioti su skaitmenimis 0 ir 1 arba tarpusavyje. Taip gaunama trumpa, lengvai perskaitoma balsu eilutė, kurią saugu tiesiogiai naudoti URL.

Kaip apskaičiuoti ULID

ULID generatorius identifikatorių sukuria trimis etapais.

  1. Nuskaitomas dabartinis laikas milisekundėmis nuo Unix epochos pradžios. Tai yra 48 bitų skaičius.
  2. Sugeneruojama 80 bitų atsitiktinių duomenų, paprastai naudojant kriptografiškai saugų atsitiktinių skaičių generatorių, gaunant 10 atsitiktinių baitų.
  3. Abi dalys užkoduojamos atskirai, naudojant Crockfordo Base32 abėcėlę: 48 bitų laiko žyma paverčiama į 10 simbolių, o 80 bitų atsitiktinė reikšmė – į 16 simbolių. Dvi užkoduotos eilutės sujungiamos ir gaunamas galutinis 26 simbolių ULID.

Kodavimas atliekamas skaitant po 5 bitus, nes kiekvienas Base32 simbolis reiškia vieną iš 32 galimų reikšmių (2^5 = 32). Dešimt simbolių talpina iki 50 bitų, todėl jų pakanka 48 bitų laiko žymai. Šešiolika simbolių talpina lygiai 80 bitų, atitinkančių atsitiktinę dalį be likučio.

Pavyzdys su sprendimu

Tarkime, ULID generatorius veikia esant laiko žymai 1712345678901 (milisekundės nuo epochos pradžios) ir gauna atsitiktinius baitus [12, 240, 88, 3, 199, 45, 6, 231, 128, 17].

Etapas 1 – užkoduojama laiko žyma. Skaičius 1712345678901 pakartotinai dalijamas iš 32, kiekvieną kartą paimant liekaną ir skaitant skaitmenis nuo paskutinio iki pirmojo (tai yra įprastas skaičių konvertavimas į kitą sistemą). Taip gaunama 10 simbolių eilutė 01HTQW311N.

Etapas 2 – užkoduojamas atsitiktinumas. 10 atsitiktinių baitų supakuojami į 80 bitų srautą, tada skaitoma po 5 bitus ir kiekvienas 5 bitų blokas paverčiamas Base32 simboliu. Taip gaunama 16 simbolių eilutė 1KR5G0Y75M3EF00H.

Etapas 3 – dalys sujungiamos. Galutinis ULID yra:

101HTQW311N 1KR5G0Y75M3EF00H
2

užrašytas be tarpo: 01HTQW311N1KR5G0Y75M3EF00H, iš viso 26 simbolių.

Šio generatoriaus naudojimas

Generatorius veikia naršyklėje. Kiekvienas ULID sudaromas iš naršyklės laikrodžio duomenų ir 80 naujų atsitiktinių bitų, paimtų iš naršyklės kriptografinio atsitiktinių skaičių generatoriaus, todėl joks identifikatorius nesiunčiamas į serverį ir iš jo negaunamas.

  • ULID skaičius priima sveikąjį skaičių nuo 1 iki 50. Numatytoji reikšmė yra 1.
  • Generuoti ULID sukuria naują paketą. Pakeitus skaičių, taip pat sukuriamas naujas paketas.
  • Paspaudus prie rezultato esantį Kopijuoti, nukopijuojamas tas vienintelis ULID. Kai rodoma daugiau nei vienas ULID, Kopijuoti visus nukopijuoja visą sąrašą, po vieną ULID eilutėje.
  • Atkurti grąžina skaičių į 1 ir sugeneruoja vieną naują ULID.

Po rezultatais esančiame ULID struktūros skydelyje pirmasis paketo ULID padalijamas į dvi dalis: pirmuosius 10 simbolių (laiko žymą) ir paskutiniuosius 16 simbolių (atsitiktinę dalį).

ULID ir UUID palyginimas

SavybėULIDUUID (versija 4)
Ilgis26 simbolių36 simboliai (su brūkšneliais)
Galima rikiuoti pagal sukūrimo laikąTaipNe
KodavimasCrockfordo Base32Šešioliktainė
Turi laiko žymąTaip (48 bitai)Ne
Saugus naudoti URL be kodavimoTaipTaip

Abiem formatais siekiama sukurti visose sistemose unikalius identifikatorius, kai numerius nesuteikia centrinė tarnyba. Pagrindinis praktinis skirtumas yra rikiavimas: kadangi ULID prasideda laiko žyma, rikiuojant ULID kaip paprastą tekstą jie taip pat surikiuojami pagal laiką. Atsitiktinis UUID tokios savybės neturi, nes kiekviena jo dalis yra atsitiktinė.

Įprastas taikymas

  • Duomenų bazės pirminiai raktai: ULID leidžia duomenų bazės indeksui naujas eilutes indeksuoti maždaug jų įterpimo tvarka, o daugelis duomenų bazių sistemų tai apdoroja efektyviau nei visiškai atsitiktinius raktus.
  • Paskirstytosios sistemos: atskiri serveriai gali savarankiškai generuoti ULID, nederindami veiksmų su centriniu skaitikliu, o gauti identifikatoriai vis tiek beveik neabejotinai bus unikalūs.
  • Įvykių žurnalai: kadangi ULID rikiuojami pagal laiką, įvykių identifikatorių sąrašas gali būti apytikslė laiko juosta.
  • API ir failų identifikatoriai: fiksuoto 26 simbolių ilgio, URL saugus formatas patogiai naudojamas žiniatinklio adresuose ir failų pavadinimuose.

Susiję identifikatorių formatai yra KSUID, kuriame taip pat koduojama laiko žyma rikiavimui, ir „Snowflake“ identifikatoriai, kuriuos naudoja „Twitter“ bei kitos organizacijos; juose sujungiama laiko žyma, įrenginio identifikatorius ir skaitiklis.

Kodo pavyzdžiai

Kiekvienas toliau pateiktas pavyzdys sukuria ULID taip, kaip aprašyta ULID specifikacijoje: 48 bitų laiko žyma užkoduojama į 10 Crockfordo Base32 simbolių seką, 80 atsitiktinių bitų užkoduojama į dar 16 simbolių, ir jie sujungiami.

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

Dažnai užduodami klausimai

Kam naudojamas ULID? ULID naudojamas kaip unikalus duomenų bazės eilutės, API ištekliaus arba žurnale užregistruoto įvykio identifikatorius tais atvejais, kai taip pat naudinga rikiuoti pagal sukūrimo laiką.

Koks ULID ilgis? ULID visada yra 26 simbolių ilgio: 10 simbolių skiriama laiko žymai ir 16 – atsitiktinei daliai.

Kokį kodavimą naudoja ULID? ULID naudoja Crockfordo Base32 abėcėlę, sudarytą iš skaitmenų 0–9 ir raidžių A–Z, iš kurių pašalintos I, L, O ir U, kad jos nebūtų painiojamos su kitais simboliais.

Kuo ULID skiriasi nuo UUID? ULID rikiuojamas pagal sukūrimo laiką ir yra 26 simbolių ilgio. Atsitiktinis (versijos 4) UUID nėra rikiuojamas pagal laiką ir yra 36 simbolių ilgio, įskaitant brūkšnelius.

Kokia dviejų ULID sutapimo tikimybė? 80 atsitiktinumo bitų užtikrina, kad sutapimai yra ypač mažai tikėtini. Kad bet kurių dviejų identifikatorių sutapimo tikimybė pasiektų 50 %, per tą pačią milisekundę reikėtų sugeneruoti maždaug 1,3 trilijono ULID.

Ar ULID galima generuoti be interneto ryšio? Taip. ULID reikia tik vietinio laikrodžio ir atsitiktinių skaičių generatoriaus, todėl jį galima sukurti visiškai neprisijungus prie interneto.

Šaltiniai

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