Pāriet uz saturu

ULID ģenerators - Izveidojiet unikālus, kārtojamus ID tiešsaistē bez maksas

Bezmaksas ULID ģeneratora rīks momentāli izveido unikālus, kārtojamus identifikatorus. Ģenerējiet kriptogrāfiski drošus ULID identifikatorus datubāzēm, API un izkliedētām sistēmām tiešsaistē.

ULID ģenerators

Ievadiet vērtību, lai redzētu rezultātus
Ielādes kalkulators...
📚

Dokumentācija

Kas ir ULID?

ULID (universāli unikāls leksikogrāfiski kārtojams identifikators) ir 26 rakstzīmju kods, ko izmanto ierakstu apzīmēšanai datubāzē vai notikuma apzīmēšanai sadalītā sistēmā. Tas apvieno pašreizējo laiku ar nejaušiem datiem, tāpēc alfabētiski sakārtots ULID saraksts tiek sakārtots arī pēc katra identifikatora izveides laika. ULID ģenerators ir rīks, kas izveido šādus kodus.

ULID struktūra

ULID sastāv no divām daļām, kas rakstītas viena aiz otras bez atdalītāja:

  • Laikspiedols (10 rakstzīmes): milisekunžu skaits kopš 1970. gada 1. janvāris (Unix laikmeta sākuma), kas aizņem līdz 48 bitiem.
  • Nejaušie dati (16 rakstzīmes): 80 biti nejaušu datu, kas pievienoti, lai divi vienā milisekundē izveidoti ULID gandrīz noteikti būtu atšķirīgi.

Abas daļas tiek rakstītas, izmantojot Crockford Base32 alfabētu: ciparus 0–9 un burtus A–Z, izņemot burtus I, L, O un U. Šie četri burti ir izlaisti, jo tos var sajaukt ar cipariem 0 un 1 vai savā starpā. Rezultāts ir īsa virkne, ko ir viegli nolasīt skaļi un droši ievietot tieši URL.

Kā aprēķināt ULID

ULID ģenerators izveido identifikatoru trīs darbībās.

  1. Nolasīt pašreizējo laiku milisekundēs kopš Unix laikmeta sākuma. Tas ir 48 bitu skaitlis.
  2. Ģenerēt 80 bitus nejaušu datu, parasti izmantojot kriptogrāfiski drošu nejaušo skaitļu ģeneratoru, iegūstot 10 nejaušus baitus.
  3. Atsevišķi kodēt abas daļas, izmantojot Crockford Base32 alfabētu: 48 bitu laikspiedols kļūst par 10 rakstzīmēm, bet 80 bitu nejaušā vērtība — par 16 rakstzīmēm. Abas kodētās virknes tiek savienotas, izveidojot galīgo 26 rakstzīmju ULID.

Kodēšana notiek, nolasot skaitli pa 5 bitiem, jo katra Base32 rakstzīme apzīmē vienu no 32 iespējamām vērtībām (2^5 = 32). Desmit rakstzīmes var saturēt līdz 50 bitiem, kas ir pietiekami 48 bitu laikspiedolam. Sešpadsmit rakstzīmes satur tieši 80 bitus, kas precīzi atbilst nejaušo datu daļai.

Atrisināts piemērs

Pieņemsim, ka ULID ģenerators darbojas ar laikspiedolu 1712345678901 (milisekundes kopš laikmeta sākuma) un iegūst nejaušos baitus [12, 240, 88, 3, 199, 45, 6, 231, 128, 17].

1. darbība — kodēt laikspiedolu. Atkārtoti daliet 1712345678901 ar 32, katru reizi ņemot atlikumu un nolasot ciparus no pēdējā līdz pirmajam (tā ir standarta pārveidošana citā skaitīšanas sistēmā). Tiek iegūta 10 rakstzīmju virkne 01HTQW311N.

2. darbība — kodēt nejaušos datus. Iepakojiet 10 nejaušos baitus 80 bitu plūsmā, pēc tam nolasiet pa 5 bitiem un katru 5 bitu bloku pārveidojiet par Base32 rakstzīmi. Tiek iegūta 16 rakstzīmju virkne 1KR5G0Y75M3EF00H.

3. darbība — savienot daļas. Galīgais ULID ir:

101HTQW311N 1KR5G0Y75M3EF00H
2

uzrakstīts bez atstarpes: 01HTQW311N1KR5G0Y75M3EF00H, kopā 26 rakstzīmes.

Šī ģeneratora izmantošana

Ģenerators darbojas pārlūkprogrammā. Katrs ULID tiek izveidots no pārlūkprogrammas pulksteņa un 80 jauniem nejaušiem bitiem, kas iegūti no pārlūkprogrammas kriptogrāfiskā nejaušo skaitļu ģeneratora, tāpēc neviens identifikators netiek nosūtīts uz serveri vai no tā izgūts.

  • ULID skaits pieņem veselu skaitli no 1 līdz 50. Noklusējuma vērtība ir 1.
  • Ģenerēt ULID izveido jaunu kopu. Mainot skaitu, tiek izveidota arī jauna kopa.
  • Kopēt pie rezultāta nokopē šo vienu ULID. Ja tiek parādīts vairāk nekā viens ULID, Kopēt visu nokopē visu sarakstu, katru ULID jaunā rindā.
  • Atiestatīt iestata skaitu atpakaļ uz 1 un ģenerē vienu jaunu ULID.

Zem rezultātiem panelis “ULID struktūra” sadala pirmo ULID kopā divās daļās: pirmās 10 rakstzīmes (laikspiedolu) un pēdējās 16 rakstzīmes (nejaušos datus).

ULID un UUID

FunkcijaULIDUUID (versija 4)
Garums26 rakstzīmes36 rakstzīmes (ar defisēm)
Kārtojams pēc izveides laikaJāNē
KodējumsCrockford Base32Heksadecimālā
Satur laikspiedoluJā (48 biti)Nē
URL drošs bez aizstājējkodēšanasJāJā

Abu formātu mērķis ir izveidot identifikatorus, kas ir unikāli dažādās sistēmās, bez centrālas iestādes, kas piešķir numurus. Galvenā praktiskā atšķirība ir kārtošana: tā kā ULID sākas ar laikspiedolu, ULID kārtošana kā vienkāršs teksts tos sakārto arī pēc laika. Nejaušam UUID šādas īpašības nav, jo katra tā daļa ir nejauša.

Biežākie lietojumi

  • Datubāzes primārās atslēgas: ULID ļauj datubāzei indeksēt jaunas rindas aptuveni ievietošanas secībā, ko daudzi datubāzu dzinēji apstrādā efektīvāk nekā pilnībā nejaušas atslēgas.
  • Sadalītās sistēmas: atsevišķi serveri var neatkarīgi ģenerēt ULID, nesaskaņojot darbības ar centrālu skaitītāju, un rezultāti joprojām gandrīz noteikti būs unikāli.
  • Notikumu žurnāli: tā kā ULID tiek kārtoti pēc laika, notikumu identifikatoru saraksts var kalpot arī kā aptuvena laika josla.
  • API un failu identifikatori: fiksētais 26 rakstzīmju, URL drošais formāts labi darbojas tīmekļa adresēs un failu nosaukumos.

Saistītie identifikatoru formāti ietver KSUID, kas arī kodē laikspiedolu kārtošanai, un Snowflake identifikatorus, ko izmanto Twitter un citi, un kas apvieno laikspiedolu, iekārtas identifikatoru un skaitītāju.

Koda piemēri

Katrs tālāk redzamais piemērs izveido ULID tādā pašā veidā, kā aprakstīts ULID specifikācijā: kodē 48 bitu laikspiedolu kā 10 Crockford Base32 rakstzīmes, kodē 80 bitus nejaušu datu kā vēl 16 rakstzīmes un savieno tās.

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

Biežāk uzdotie jautājumi

Kam izmanto ULID? ULID izmanto kā unikālu datubāzes rindas, API resursa vai reģistrēta notikuma identifikatoru gadījumos, kad noder arī kārtošana pēc izveides laika.

Cik garš ir ULID? ULID vienmēr ir 26 rakstzīmes garš: 10 rakstzīmes ir laikspiedolam un 16 — nejaušo datu daļai.

Kādu kodējumu izmanto ULID? ULID izmanto Crockford Base32 alfabētu, ko veido cipari 0–9 un burti A–Z, no kuriem izņemti I, L, O un U, lai izvairītos no sajaukšanas ar citām rakstzīmēm.

Kā ULID atšķiras no UUID? ULID tiek kārtots pēc izveides laika un ir 26 rakstzīmes garš. Nejaušs (versijas 4) UUID netiek kārtots pēc laika un ir 36 rakstzīmes garš, ieskaitot defises.

Cik iespējama ir sadursme starp diviem ULID? 80 nejaušības biti padara sadursmes ārkārtīgi maz ticamas. Lai sasniegtu 50% varbūtību, ka kādi divi ULID sakritīs, vienā milisekundē būtu jāģenerē aptuveni 1,3 triljoni ULID.

Vai ULID var ģenerēt bez interneta savienojuma? Jā. ULID vajadzīgs tikai lokālais pulkstenis un nejaušo skaitļu ģenerators, tāpēc to var pilnībā izveidot bezsaistē.

Atsauces

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