ULID Generator - Opret Entydige Sorterbare ID'er Online Gratis
Gratis ULID-generatorværktøj opretter entydige, sorterbare identifikatorer øjeblikkeligt. Generer kryptografisk sikre ULID'er til databaser, API'er og distribuerede systemer online.
ULID Generator
Dokumentation
Hvad er en ULID?
En ULID (Universally Unique Lexicographically Sortable Identifier) er en kode på 26 tegn, der bruges til at mærke poster i en database eller en hændelse i et distribueret system. Den kombinerer det aktuelle tidspunkt med tilfældige data, så en liste over ULID'er sorteret alfabetisk ender med at være sorteret efter det tidspunkt, hvor hver enkelt blev oprettet. En ULID-generator er et værktøj, der producerer disse koder.
ULID-struktur
En ULID består af to dele, skrevet efter hinanden uden skilletegn:
- Tidsstempel (10 tegn): antallet af millisekunder siden 1. januar 1970 (Unix-epoken), dækket af op til 48 bit.
- Tilfældighed (16 tegn): 80 bit tilfældige data, tilføjet så to ULID'er, der oprettes i samme millisekund, næsten med sikkerhed stadig er forskellige.
Begge dele skrives med Crockfords Base32-alfabet: cifrene 0–9 og bogstaverne A-Z minus bogstaverne I, L, O og U. De fire bogstaver udelades, fordi de kan forveksles med cifrene 0 og 1 eller med hinanden. Resultatet er en streng, der er kort, nem at læse højt og sikker at indsætte direkte i en URL.
Sådan beregnes en ULID
En ULID-generator opbygger en identifikator i tre trin.
- Læs det aktuelle tidspunkt i millisekunder siden Unix-epoken. Dette er et tal på 48 bit.
- Generér 80 bit tilfældige data, normalt fra en kryptografisk sikker slumptalsgenerator, hvilket giver 10 tilfældige bytes.
- Kod de to dele hver for sig med Crockfords Base32-alfabet: Tidsstemplet på 48 bit bliver til 10 tegn, og den tilfældige værdi på 80 bit bliver til 16 tegn. De to kodede strenge sættes sammen til den endelige ULID på 26 tegn.
Kodningen fungerer ved at læse tallet 5 bit ad gangen, fordi hvert Base32-tegn repræsenterer en af 32 mulige værdier (2^5 = 32). Ti tegn rummer op til 50 bit, hvilket er nok plads til tidsstemplet på 48 bit. Seksten tegn rummer præcis 80 bit, hvilket svarer til tilfældighedsdelen uden noget tilovers.
Regneeksempel
Antag, at en ULID-generator kører ved tidsstemplet 1712345678901 (millisekunder siden epoken) og trækker de tilfældige bytes [12, 240, 88, 3, 199, 45, 6, 231, 128, 17].
Trin 1 – kod tidsstemplet. Divider gentagne gange 1712345678901 med 32, tag resten hver gang, og læs cifrene fra det sidste til det første (dette er en standardkonvertering mellem talbaser). Det giver strengen på 10 tegn, 01HTQW311N.
Trin 2 – kod tilfældigheden. Pak de 10 tilfældige bytes i en strøm af 80 bit, og aflæs derefter 5 bit ad gangen, hvor hvert stykke på 5 bit konverteres til et Base32-tegn. Det giver strengen på 16 tegn, 1KR5G0Y75M3EF00H.
Trin 3 – sæt delene sammen. Den endelige ULID er:
101HTQW311N 1KR5G0Y75M3EF00H
2skrevet uden mellemrum: 01HTQW311N1KR5G0Y75M3EF00H, i alt 26 tegn.
Brug af denne generator
Generatoren kører i browseren. Hver ULID opbygges ud fra browserens ur og 80 nye tilfældige bit fra browserens kryptografiske slumptalsgenerator, så ingen identifikator sendes til eller hentes fra en server.
- Antal ULID'er accepterer et helt tal fra 1 til 50. Standardværdien er 1.
- Generér ULID producerer en ny gruppe. Hvis antallet ændres, produceres der også en ny gruppe.
- Kopiér ved et resultat kopierer den enkelte ULID. Når der vises mere end én, kopierer Kopiér alle hele listen med én ULID pr. linje.
- Nulstil sætter antallet tilbage til 1 og genererer én ny ULID.
Under resultaterne opdeler panelet ULID-struktur den første ULID i gruppen i dens to dele: de første 10 tegn (tidsstemplet) og de sidste 16 (tilfældigheden).
ULID sammenlignet med UUID
| Funktion | ULID | UUID (version 4) |
|---|---|---|
| Længde | 26 tegn | 36 tegn (med bindestreger) |
| Kan sorteres efter oprettelsestidspunkt | Ja | Nej |
| Kodning | Crockford Base32 | Hexadecimal |
| Indeholder et tidsstempel | Ja (48 bit) | Nej |
| URL-sikker uden escaping | Ja | Ja |
Begge formater sigter mod at producere identifikatorer, der er unikke på tværs af systemer uden en central instans, der udsteder numre. Den vigtigste praktiske forskel er sorteringen: fordi en ULID begynder med et tidsstempel, sorteres ULID'er som almindelig tekst også efter tid. En tilfældig UUID har ikke denne egenskab, eftersom alle dens dele er tilfældige.
Almindelige anvendelser
- Primærnøgler i databaser: ULID'er gør det muligt for en database at indeksere nye rækker omtrent i den rækkefølge, de blev indsat, hvilket mange databasemotorer håndterer mere effektivt end helt tilfældige nøgler.
- Distribuerede systemer: separate servere kan hver især generere ULID'er uafhængigt uden koordinering med en central tæller, og resultaterne er stadig næsten med sikkerhed unikke.
- Hændelseslogge: fordi ULID'er sorteres efter tid, kan en liste over hændelses-id'er også fungere som en omtrentlig tidslinje.
- API- og filidentifikatorer: det faste, URL-sikre format med 26 tegn fungerer problemfrit i webadresser og filnavne.
Relaterede identifikatorformater omfatter KSUID, som også koder et tidsstempel til sortering, og Snowflake-id'er, der bruges af Twitter og andre, og som kombinerer et tidsstempel, en maskinidentifikator og en tæller.
Kodeeksempler
Hvert eksempel nedenfor opbygger en ULID på samme måde, som ULID-specifikationen beskriver: Kod tidsstemplet på 48 bit som 10 Crockford Base32-tegn, kod 80 bit tilfældighed som yderligere 16 tegn, og sæt dem sammen.
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}
41Ofte stillede spørgsmål
Hvad bruges en ULID til? En ULID bruges som en unik identifikator for en databasepost, en API-ressource eller en logget hændelse i tilfælde, hvor det også er nyttigt at kunne sortere efter oprettelsestidspunkt.
Hvor lang er en ULID? En ULID er altid 26 tegn lang: 10 tegn til tidsstemplet og 16 til den tilfældige del.
Hvilken kodning bruger en ULID? En ULID bruger Crockfords Base32-alfabet, som består af cifrene 0–9 og bogstaverne A-Z, hvor I, L, O og U er fjernet for at undgå forveksling med andre tegn.
Hvordan adskiller en ULID sig fra en UUID? En ULID sorteres efter oprettelsestidspunktet og er 26 tegn lang. En tilfældig UUID (version 4) sorteres ikke efter tid og er 36 tegn lang inklusive bindestreger.
Hvor sandsynligt er et sammenfald mellem to ULID'er? De 80 bit tilfældighed gør sammenfald ekstremt usandsynlige. Der skal genereres omtrent 1,3 billioner ULID'er inden for samme millisekund for at nå en 50 % sandsynlighed for, at to af dem matcher.
Kan ULID'er genereres uden internetforbindelse? Ja. En ULID kræver kun det lokale ur og en slumptalsgenerator, så den kan oprettes helt offline.
Referencer
- "ULID Specification." GitHub, https://github.com/ulid/spec.
- "Crockford's Base32 Encoding." http://www.crockford.com/base32.html.