ULID-Generator - Erstellen Sie einzigartige sortierbare IDs online kostenlos
Kostenfreies ULID-Generator-Tool erstellt sofort eindeutige, sortierbare Identifikatoren. Generieren Sie kryptografisch sichere ULIDs für Datenbanken, APIs und verteilte Systeme online.
ULID-Generator
Dokumentation
Was ist eine ULID?
Eine ULID (Universally Unique Lexicographically Sortable Identifier, universell eindeutiger lexikografisch sortierbarer Bezeichner) ist ein Code mit 26 Zeichen, der Datensätze in einer Datenbank oder ein Ereignis in einem verteilten System kennzeichnet. Sie kombiniert die aktuelle Zeit mit Zufallsdaten, sodass eine alphabetisch sortierte Liste von ULIDs letztlich nach dem Erstellungszeitpunkt sortiert ist. Ein ULID-Generator ist ein Werkzeug, das diese Codes erzeugt.
Aufbau einer ULID
Eine ULID besteht aus zwei Teilen, die ohne Trennzeichen direkt hintereinander geschrieben werden:
- Zeitstempel (10 Zeichen): die Anzahl der Millisekunden seit 1. Januar 1970 (der Unix-Epoche), dargestellt mit bis zu 48 Bits.
- Zufallsanteil (16 Zeichen): 80 Bits Zufallsdaten, damit zwei in derselben Millisekunde erzeugte ULIDs mit nahezu vollständiger Sicherheit verschieden sind.
Beide Teile werden mit Crockfords Base32-Alphabet geschrieben: den Ziffern 0–9 und den Buchstaben A–Z, abzüglich der Buchstaben I, L, O und U. Diese vier Buchstaben werden ausgelassen, weil sie mit den Ziffern 0 und 1 oder miteinander verwechselt werden können. Das Ergebnis ist eine kurze, leicht vorzulesende Zeichenfolge, die direkt in einer URL verwendet werden kann.
So wird eine ULID berechnet
Ein ULID-Generator erstellt einen Bezeichner in drei Schritten.
- Aktuelle Zeit ablesen in Millisekunden seit der Unix-Epoche. Dies ist eine Zahl mit 48 Bits.
- 80 Bits Zufallsdaten erzeugen, normalerweise mit einem kryptografisch sicheren Zufallszahlengenerator; daraus ergeben sich 10 Zufallsbytes.
- Beide Teile getrennt codieren und dabei Crockfords Base32-Alphabet verwenden: Der 48-Bit-Zeitstempel wird zu 10 Zeichen, und der 80-Bit-Zufallswert wird zu 16 Zeichen. Die beiden codierten Zeichenfolgen werden zum endgültigen ULID mit 26 Zeichen verbunden.
Die Codierung erfolgt, indem jeweils 5 Bits gelesen werden, da jedes Base32-Zeichen einen von 32 möglichen Werten (2^5 = 32) darstellt. Zehn Zeichen können bis zu 50 Bits aufnehmen, genug für den 48-Bit-Zeitstempel. Sechzehn Zeichen enthalten genau 80 Bits, was dem Zufallsanteil entspricht, ohne Rest.
Rechenbeispiel
Angenommen, ein ULID-Generator läuft beim Zeitstempel 1712345678901 (Millisekunden seit der Epoche) und zieht die Zufallsbytes [12, 240, 88, 3, 199, 45, 6, 231, 128, 17].
Schritt 1 – den Zeitstempel codieren. 1712345678901 wird wiederholt durch 32 geteilt. Dabei wird jedes Mal der Rest genommen und die Ziffern von hinten nach vorn gelesen (dies ist die übliche Umrechnung in ein Zahlensystem). Das ergibt die Zeichenfolge mit 10 Zeichen 01HTQW311N.
Schritt 2 – den Zufallsanteil codieren. Die 10 Zufallsbytes werden zu einem Strom aus 80 Bits zusammengefasst. Anschließend werden jeweils 5 Bits gelesen und jeder 5-Bit-Abschnitt in ein Base32-Zeichen umgewandelt. Das ergibt die Zeichenfolge mit 16 Zeichen 1KR5G0Y75M3EF00H.
Schritt 3 – die Teile verbinden. Die vollständige ULID lautet:
101HTQW311N 1KR5G0Y75M3EF00H
2ohne Leerzeichen: 01HTQW311N1KR5G0Y75M3EF00H, insgesamt 26 Zeichen.
Diesen Generator verwenden
Der Generator läuft im Browser. Jede ULID wird aus der Browseruhr und 80 neuen Zufallsbits erzeugt, die dem kryptografischen Zufallszahlengenerator des Browsers entnommen werden. Daher wird kein Bezeichner an einen Server gesendet oder von dort abgerufen.
- Anzahl der ULIDs akzeptiert eine ganze Zahl von 1 bis 50. Der Standardwert ist 1.
- ULID erzeugen erstellt einen neuen Stapel. Auch eine Änderung der Anzahl erzeugt einen neuen Stapel.
- Kopieren bei einem Ergebnis kopiert diese einzelne ULID. Wenn mehrere angezeigt werden, kopiert Alle kopieren die gesamte Liste, eine ULID pro Zeile.
- Zurücksetzen setzt die Anzahl auf 1 zurück und erzeugt eine neue ULID.
Unter den Ergebnissen teilt das Bedienfeld „ULID-Struktur“ die erste ULID des Stapels in ihre beiden Teile auf: die ersten 10 Zeichen (den Zeitstempel) und die letzten 16 Zeichen (den Zufallsanteil).
ULID im Vergleich zu UUID
| Merkmal | ULID | UUID (Version 4) |
|---|---|---|
| Länge | 26 Zeichen | 36 Zeichen (mit Bindestrichen) |
| Nach Erstellungszeit sortierbar | Ja | Nein |
| Encoding | Crockford-Base32 | Hexadezimal |
| Enthält einen Zeitstempel | Ja (48 Bits) | Nein |
| URL-sicher ohne Escape-Codierung | Ja | Ja |
Beide Formate sollen Bezeichner erzeugen, die in verschiedenen Systemen ohne zentrale Vergabestelle eindeutig sind. Der wichtigste praktische Unterschied ist die Sortierung: Da eine ULID mit einem Zeitstempel beginnt, werden ULIDs beim Sortieren als einfacher Text auch nach der Zeit sortiert. Eine zufällige UUID hat diese Eigenschaft nicht, da jeder Teil zufällig ist.
Häufige Anwendungen
- Primärschlüssel in Datenbanken: ULIDs ermöglichen es einer Datenbank, neue Zeilen ungefähr in der Reihenfolge ihrer Einfügung zu indizieren. Viele Datenbank-Engines verarbeiten dies effizienter als vollständig zufällige Schlüssel.
- Verteilte Systeme: Getrennte Server können jeweils unabhängig ULIDs erzeugen, ohne sich mit einem zentralen Zähler abzustimmen; die Ergebnisse sind dennoch mit nahezu vollständiger Sicherheit eindeutig.
- Ereignisprotokolle: Da ULIDs nach der Zeit sortiert werden, kann eine Liste von Ereignis-IDs zugleich als grobe Zeitachse dienen.
- API- und Dateibezeichner: Das feste, URL-sichere Format mit 26 Zeichen funktioniert problemlos in Webadressen und Dateinamen.
Zu den verwandten Bezeichnerformaten gehören KSUID, das ebenfalls einen Zeitstempel zur Sortierung codiert, und Snowflake-IDs, die von Twitter und anderen verwendet werden und einen Zeitstempel, einen Rechnerbezeichner und einen Zähler kombinieren.
Codebeispiele
Jedes folgende Beispiel erstellt eine ULID auf die gleiche Weise, wie es die ULID-Spezifikation beschreibt: Es codiert den 48-Bit-Zeitstempel als 10 Crockford-Base32-Zeichen, codiert 80 Bits Zufallsdaten als weitere 16 Zeichen und verbindet beide Teile.
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}
41Häufig gestellte Fragen
Wofür wird eine ULID verwendet? Eine ULID dient als eindeutiger Bezeichner für eine Datenbankzeile, eine API-Ressource oder ein protokolliertes Ereignis, wenn zusätzlich eine Sortierung nach dem Erstellungszeitpunkt sinnvoll ist.
Wie lang ist eine ULID? Eine ULID ist immer 26 Zeichen lang: 10 Zeichen für den Zeitstempel und 16 für den Zufallsanteil.
Welche Codierung verwendet eine ULID? Eine ULID verwendet Crockfords Base32-Alphabet aus den Ziffern 0–9 und den Buchstaben A–Z, wobei I, L, O und U entfernt wurden, um Verwechslungen mit anderen Zeichen zu vermeiden.
Wie unterscheidet sich eine ULID von einer UUID? Eine ULID wird nach dem Erstellungszeitpunkt sortiert und ist 26 Zeichen lang. Eine zufällige UUID (Version 4) wird nicht nach der Zeit sortiert und ist einschließlich Bindestrichen 36 Zeichen lang.
Wie wahrscheinlich ist eine Kollision zwischen zwei ULIDs? Die 80 Bits Zufallsdaten machen Kollisionen äußerst unwahrscheinlich. Es müssten ungefähr 1,3 Billionen ULIDs innerhalb derselben Millisekunde erzeugt werden, damit die Wahrscheinlichkeit einer Übereinstimmung zweier ULIDs 50 % erreicht.
Können ULIDs ohne Internetverbindung erzeugt werden? Ja. Eine ULID benötigt nur die lokale Uhr und einen Zufallszahlengenerator und kann daher vollständig offline erstellt werden.
Referenzen
- "ULID Specification." GitHub, https://github.com/ulid/spec.
- "Crockford's Base32 Encoding." http://www.crockford.com/base32.html.