ULID Generator - Opprett Unike Sorterbare ID-er Gratis på Nett
Gratis ULID-generatorverktøy som oppretter unike, sorterbare identifikatorer umiddelbart. Generer kryptografisk sikre ULID-er for databaser, API-er og distribuerte systemer på nettet.
ULID Generator
Dokumentasjon
Hva er en ULID?
En ULID (Universally Unique Lexicographically Sortable Identifier) er en kode på 26 tegn som brukes til å merke poster i en database eller en hendelse i et distribuert system. Den kombinerer gjeldende tidspunkt med tilfeldige data, slik at en liste med ULID-er som sorteres alfabetisk, også blir sortert etter tidspunktet hver av dem ble opprettet. En ULID-generator er et verktøy som produserer slike koder.
ULID-struktur
En ULID har to deler, skrevet etter hverandre uten skilletegn:
- Tidsstempel (10 tegn): antallet millisekunder siden 1. januar 1970 (Unix-epoken), med opptil 48 biter.
- Tilfeldighet (16 tegn): 80 biter med tilfeldig data, lagt til slik at to ULID-er som opprettes i samme millisekund, nesten helt sikkert fortsatt er forskjellige.
Begge delene skrives med Crockfords Base32-alfabet: sifrene 0–9 og bokstavene A–Z, bortsett fra I, L, O og U. Disse fire bokstavene utelates fordi de kan forveksles med sifrene 0 og 1 eller med hverandre. Resultatet er en streng som er kort, enkel å lese høyt og trygg å sette direkte inn i en URL.
Slik beregnes en ULID
En ULID-generator bygger en identifikator i tre trinn.
- Les av gjeldende tidspunkt i millisekunder siden Unix-epoken. Dette er et tall på 48 biter.
- Generer 80 biter med tilfeldige data, vanligvis fra en kryptografisk sikker generator for tilfeldige tall, som gir 10 tilfeldige byte.
- Kod begge delene separat med Crockfords Base32-alfabet: tidsstempelet på 48 biter blir til 10 tegn, og den tilfeldige verdien på 80 biter blir til 16 tegn. De to kodede strengene settes sammen til den endelige ULID-en på 26 tegn.
Kodingen fungerer ved å lese tallet 5 biter om gangen, fordi hvert Base32-tegn representerer én av 32 mulige verdier (2^5 = 32). Ti tegn rommer opptil 50 biter, som er nok plass til tidsstempelet på 48 biter. Seksten tegn rommer nøyaktig 80 biter, noe som tilsvarer tilfeldighetsdelen uten noe til overs.
Regneeksempel
Anta at en ULID-generator kjører med tidsstempelet 1712345678901 (millisekunder siden epoken) og trekker de tilfeldige bytene [12, 240, 88, 3, 199, 45, 6, 231, 128, 17].
Trinn 1 – kod tidsstempelet. Del 1712345678901 gjentatte ganger på 32, ta resten hver gang og les sifrene fra siste til første (dette er standard basiskonvertering). Dette gir strengen på 10 tegn 01HTQW311N.
Trinn 2 – kod tilfeldighetsdelen. Pakk de 10 tilfeldige bytene inn i en strøm på 80 biter, og les deretter 5 biter om gangen. Konverter hver blokk på 5 biter til et Base32-tegn. Dette gir strengen på 16 tegn 1KR5G0Y75M3EF00H.
Trinn 3 – sett delene sammen. Den endelige ULID-en er:
101HTQW311N 1KR5G0Y75M3EF00H
2skrevet uten mellomrom: 01HTQW311N1KR5G0Y75M3EF00H, totalt 26 tegn.
Bruke denne generatoren
Generatoren kjører i nettleseren. Hver ULID bygges fra nettleserens klokke og 80 nye tilfeldige biter hentet fra nettleserens kryptografiske slumptallsgenerator, slik at ingen identifikator sendes til eller hentes fra en server.
- Antall ULID-er godtar et helt tall fra 1 til 50. Standardverdien er 1.
- Generer ULID lager en ny gruppe. Hvis antallet endres, lages også en ny gruppe.
- Kopier på et resultat kopierer den ene ULID-en. Når flere vises, kopierer Kopier alle hele listen, med én ULID per linje.
- Tilbakestill setter antallet tilbake til 1 og genererer én ny ULID.
Under resultatene deler ULID-struktur-panelet den første ULID-en i gruppen i de to delene: de første 10 tegnene (tidsstempelet) og de siste 16 (tilfeldigheten).
ULID sammenlignet med UUID
| Funksjon | ULID | UUID (versjon 4) |
|---|---|---|
| Lengde | 26 tegn | 36 tegn (med bindestreker) |
| Kan sorteres etter opprettelsestidspunkt | Ja | Nei |
| Koding | Crockford Base32 | Heksadesimal |
| Inneholder et tidsstempel | Ja (48 biter) | Nei |
| URL-sikker uten escaping | Ja | Ja |
Begge formatene skal produsere identifikatorer som er unike på tvers av systemer, uten at en sentral instans deler ut numre. Den viktigste praktiske forskjellen er sortering: Siden en ULID begynner med et tidsstempel, sorteres ULID-er også etter tid når de sorteres som ren tekst. En tilfeldig UUID har ikke denne egenskapen, siden alle delene av den er tilfeldige.
Vanlige bruksområder
- Primærnøkler i databaser: ULID-er gjør at en database kan indeksere nye rader omtrent i den rekkefølgen de ble satt inn, noe mange databasemotorer håndterer mer effektivt enn helt tilfeldige nøkler.
- Distribuerte systemer: Separate servere kan generere ULID-er uavhengig av hverandre, uten å samordne seg med en sentral teller, og resultatene er fortsatt nesten helt sikkert unike.
- Hendelseslogger: Siden ULID-er sorteres etter tid, kan en liste over hendelses-ID-er også fungere som en omtrentlig tidslinje.
- API- og filidentifikatorer: Formatet på fast 26 tegn, som er URL-sikkert, fungerer godt i nettadresser og filnavn.
Beslektede identifikatorformater omfatter KSUID, som også koder et tidsstempel for sortering, og Snowflake-ID-er, som brukes av Twitter og andre, og som kombinerer et tidsstempel, en maskinidentifikator og en teller.
Kodeeksempler
Hvert eksempel nedenfor bygger en ULID på samme måte som ULID-spesifikasjonen beskriver: Kod tidsstempelet på 48 biter som 10 Crockford Base32-tegn, kod 80 biter med tilfeldighet som ytterligere 16 tegn, og sett 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 stilte spørsmål
Hva brukes en ULID til? En ULID brukes som en unik identifikator for en rad i en database, en API-ressurs eller en logget hendelse når det også er nyttig å kunne sortere etter opprettelsestidspunkt.
Hvor lang er en ULID? En ULID er alltid 26 tegn lang: 10 tegn for tidsstempelet og 16 for den tilfeldige delen.
Hvilken koding bruker en ULID? En ULID bruker Crockfords Base32-alfabet, som består av sifrene 0–9 og bokstavene A–Z, der I, L, O og U er fjernet for å unngå forveksling med andre tegn.
Hvordan skiller en ULID seg fra en UUID? En ULID sorteres etter opprettelsestidspunkt og er 26 tegn lang. En tilfeldig UUID (versjon 4) sorteres ikke etter tid og er 36 tegn lang, inkludert bindestreker.
Hvor sannsynlig er en kollisjon mellom to ULID-er? De 80 tilfeldige bitene gjør kollisjoner svært usannsynlige. Det ville kreves at omtrent 1,3 billioner ULID-er ble generert i løpet av samme millisekund for å nå en 50 % sjanse for at to av dem er like.
Kan ULID-er genereres uten internettilkobling? Ja. En ULID trenger bare den lokale klokken og en slumptallsgenerator, så den kan opprettes helt uten nett.
Referanser
- "ULID Specification." GitHub, https://github.com/ulid/spec.
- "Crockford's Base32 Encoding." http://www.crockford.com/base32.html.