ULID генератор - Създайте уникални сортируеми идентификатори онлайн безплатно
Безплатен инструмент за генериране на ULID, който създава уникални, сортируеми идентификатори мигновено. Генерирайте криптографски сигурни ULID за бази данни, API и разпределени системи онлайн.
ULID генератор
Документация
Какво представлява ULID?
ULID (универсално уникален лексикографски сортиращ се идентификатор) е код от 26 знака, използван за обозначаване на записи в база данни или на събитие в разпределена система. Той съчетава текущото време със случайни данни, така че списък с ULID-и, сортиран по азбучен ред, се оказва сортиран според времето на създаване на всеки идентификатор. Генераторът на ULID е инструмент, който създава тези кодове.
Структура на ULID
ULID има две части, изписани една след друга без разделител:
- Времеви отпечатък (10 знака): броят милисекунди от 1 януари 1970 г. (Unix епохата), представен с до 48 бита.
- Случайност (16 знака): 80 бита случайни данни, добавени така, че два ULID-а, създадени в рамките на една и съща милисекунда, почти сигурно да са различни.
И двете части се изписват с азбуката Crockford Base32: цифрите 0–9 и буквите A–Z без буквите I, L, O и U. Тези четири букви са пропуснати, защото могат да бъдат сбъркани с цифрите 0 и 1 или една с друга. Резултатът е кратък низ, който се чете лесно на глас и може безопасно да се поставя директно в URL адрес.
Как се изчислява ULID
Генераторът на ULID създава идентификатор в три стъпки.
- Отчитане на текущото време в милисекунди от началната дата на Unix. Това е число с 48 бита.
- Генериране на 80 бита случайни данни, обикновено от генератор на криптографски сигурни случайни числа, което дава 10 случайни байта.
- Кодиране на двете части поотделно с азбуката Crockford Base32: времевият отпечатък с 48 бита става 10 знака, а случайната стойност с 80 бита става 16 знака. Двата кодирани низа се съединяват, за да образуват крайния ULID от 26 знака.
При кодирането числото се прочита по 5 бита наведнъж, защото всеки знак от Base32 представя една от 32 възможни стойности (2^5 = 32). Десет знака побират до 50 бита, което е достатъчно за времевия отпечатък с 48 бита. Шестнадесет знака побират точно 80 бита, колкото са нужни за случайната част, без остатък.
Решен пример
Да предположим, че генераторът на ULID работи при времеви отпечатък 1712345678901 (милисекунди от началната дата) и получава случайните байтове [12, 240, 88, 3, 199, 45, 6, 231, 128, 17].
Стъпка 1 – кодиране на времевия отпечатък. Делете многократно 1712345678901 на 32, като всеки път вземате остатъка и четете цифрите от последната към първата (това е стандартно преобразуване в друга бройна система). Получава се низът от 10 знака 01HTQW311N.
Стъпка 2 – кодиране на случайните данни. Подредете 10-те случайни байта в поток от 80 бита, след което отчитайте по 5 бита наведнъж и преобразувайте всеки блок от 5 бита в знак от Base32. Получава се низът от 16 знака 1KR5G0Y75M3EF00H.
Стъпка 3 – съединяване на частите. Крайният ULID е:
101HTQW311N 1KR5G0Y75M3EF00H
2изписан без интервал: 01HTQW311N1KR5G0Y75M3EF00H, общо 26 знака.
Използване на този генератор
Генераторът работи в браузъра. Всеки ULID се създава от часовника на браузъра и 80 нови случайни бита, получени от криптографския генератор на случайни числа на браузъра, така че нито един идентификатор не се изпраща към сървър и не се извлича от него.
- Брой ULID-и приема цяло число от 1 до 50. Стойността по подразбиране е 1.
- Генериране на ULID създава нова партида. Промяната на броя също създава нова партида.
- Копиране при даден резултат копира само този ULID. Когато са показани повече от един, Копиране на всички копира целия списък, по един ULID на ред.
- Нулиране връща броя към 1 и генерира един нов ULID.
Под резултатите панелът „Структура на ULID“ разделя първия ULID от партидата на двете му части: първите 10 знака (времевият отпечатък) и последните 16 (случайната част).
ULID срещу UUID
| Функция | ULID | UUID (версия 4) |
|---|---|---|
| Дължина | 26 знака | 36 знака (с тирета) |
| Може да се сортира по време на създаване | Да | Не |
| Кодиране | Crockford Base32 | Шестнадесетична |
| Съдържа времеви отпечатък | Да (48 бита) | Не |
| Безопасен за URL адреси, без екраниране | Да | Да |
И двата формата имат за цел да създават идентификатори, уникални в различни системи, без централен орган да раздава номера. Основната практическа разлика е сортирането: тъй като ULID започва с времеви отпечатък, сортирането на ULID-и като обикновен текст ги подрежда и по време. Случайният UUID няма това свойство, тъй като всяка негова част е случайна.
Обичайни приложения
- Първични ключове в бази данни: ULID-ите позволяват на база данни да индексира новите редове приблизително в реда на вмъкването им, което много системи за управление на бази данни обработват по-ефективно от напълно случайни ключове.
- Разпределени системи: отделни сървъри могат самостоятелно да генерират ULID-и, без да се координират с централен брояч, като резултатите почти сигурно остават уникални.
- Журнали на събития: тъй като ULID-ите се сортират по време, списъкът с идентификатори на събития може да служи и като приблизителна времева линия.
- Идентификатори за API и файлове: фиксираният формат с 26 знака, безопасен за URL адреси, работи без проблеми в уеб адреси и имена на файлове.
Свързаните формати за идентификатори включват KSUID, който също кодира времеви отпечатък за сортиране, и идентификаторите Snowflake, използвани от Twitter и други услуги, които съчетават времеви отпечатък, идентификатор на машина и брояч.
Примери с код
Всеки пример по-долу създава ULID по същия начин, описан в спецификацията на ULID: времевият отпечатък с 48 бита се кодира като 10 знака Crockford Base32, 80 бита случайни данни се кодират като още 16 знака и двете части се съединяват.
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}
41Често задавани въпроси
За какво се използва ULID? ULID се използва като уникален идентификатор за ред в база данни, ресурс на API или записано събитие, когато е полезно и сортиране по време на създаване.
Колко дълъг е един ULID? ULID винаги е дълъг 26 знака: 10 знака за времевия отпечатък и 16 за случайната част.
Какво кодиране използва ULID? ULID използва азбуката Crockford Base32, съставена от цифрите 0–9 и буквите A–Z, като I, L, O и U са премахнати, за да се избегне объркване с други знаци.
По какво ULID се различава от UUID? ULID се сортира по време на създаване и е дълъг 26 знака. Случаен UUID (версия 4) не се сортира по време и е дълъг 36 знака, включително тиретата.
Колко е вероятно да възникне колизия между два ULID-а? 80-те бита случайни данни правят колизиите изключително малко вероятни. За достигане на 50% вероятност за съвпадение на два ULID-а би трябвало да се генерират приблизително 1,3 трилиона ULID-а в рамките на една и съща милисекунда.
Могат ли ULID-и да се генерират без интернет връзка? Да. За създаването на ULID са нужни само локалният часовник и генератор на случайни числа, така че той може да бъде създаден изцяло офлайн.
Източници
- "ULID Specification." GitHub, https://github.com/ulid/spec.
- "Crockford's Base32 Encoding." http://www.crockford.com/base32.html.