Generator ULID - Buat ID Unik yang Dapat Diurutkan Secara Daring Gratis
Alat generator ULID gratis membuat pengidentifikasi unik dan dapat diurutkan secara instan. Hasilkan ULID yang aman secara kriptografis untuk basis data, API & sistem terdistribusi secara daring.
Generator ULID
Dokumentasi
Apa Itu ULID?
ULID (Universally Unique Lexicographically Sortable Identifier atau Pengidentifikasi yang Dapat Diurutkan Secara Leksikografis dan Unik Secara Universal) adalah kode sepanjang 26 karakter yang digunakan untuk memberi label pada catatan dalam basis data atau suatu peristiwa dalam sistem terdistribusi. Kode ini menggabungkan waktu saat ini dengan data acak, sehingga daftar ULID yang diurutkan secara alfabetis pada akhirnya terurut berdasarkan waktu pembuatannya. Generator ULID adalah alat yang menghasilkan kode-kode ini.
Struktur ULID
ULID memiliki dua bagian, yang ditulis berurutan tanpa pemisah:
- Stempel waktu (10 karakter): jumlah milidetik sejak 1 Januari 1970 (epoch Unix), yang mencakup hingga 48 bit.
- Keacakan (16 karakter): 80 bit data acak, ditambahkan agar dua ULID yang dibuat pada milidetik yang sama hampir pasti tetap berbeda.
Kedua bagian ditulis menggunakan alfabet Base32 Crockford: digit 0–9 dan huruf A-Z, tanpa huruf I, L, O, dan U. Keempat huruf tersebut dihilangkan karena dapat tertukar dengan digit 0 dan 1, atau satu sama lain. Hasilnya adalah string yang pendek, mudah dibaca keras-keras, dan aman ditempatkan langsung dalam URL.
Cara Menghitung ULID
Generator ULID membentuk pengidentifikasi dalam tiga langkah.
- Baca waktu saat ini dalam milidetik sejak epoch Unix. Ini adalah bilangan 48 bit.
- Hasilkan 80 bit data acak, biasanya dari generator bilangan acak yang aman secara kriptografis, sehingga menghasilkan 10 byte acak.
- Enkode kedua bagian secara terpisah menggunakan alfabet Base32 Crockford: stempel waktu 48 bit menjadi 10 karakter, dan nilai acak 80 bit menjadi 16 karakter. Kedua string yang telah dienkode digabungkan untuk membentuk ULID akhir sepanjang 26 karakter.
Pengenkodean dilakukan dengan membaca bilangan sebanyak 5 bit setiap kali, karena setiap karakter Base32 mewakili salah satu dari 32 kemungkinan nilai (2^5 = 32). Sepuluh karakter dapat memuat hingga 50 bit, yang cukup untuk stempel waktu 48 bit. Enam belas karakter memuat tepat 80 bit, sesuai dengan bagian keacakan tanpa sisa.
Contoh perhitungan
Misalkan generator ULID berjalan pada stempel waktu 1712345678901 (milidetik sejak epoch) dan mengambil byte acak [12, 240, 88, 3, 199, 45, 6, 231, 128, 17].
Langkah 1 – enkode stempel waktu. Bagi 1712345678901 berulang kali dengan 32, ambil sisanya setiap kali, lalu baca digit dari yang terakhir ke yang pertama (ini adalah konversi basis standar). Hasilnya adalah string sepanjang 10 karakter, yaitu 01HTQW311N.
Langkah 2 – enkode keacakan. Kemas 10 byte acak ke dalam aliran 80 bit, lalu baca 5 bit setiap kali dan ubah setiap potongan 5 bit menjadi karakter Base32. Hasilnya adalah string sepanjang 16 karakter, yaitu 1KR5G0Y75M3EF00H.
Langkah 3 – gabungkan bagian-bagian tersebut. ULID akhirnya adalah:
101HTQW311N 1KR5G0Y75M3EF00H
2ditulis tanpa spasi: 01HTQW311N1KR5G0Y75M3EF00H, dengan total 26 karakter.
Menggunakan Generator Ini
Generator berjalan di browser. Setiap ULID dibentuk dari jam browser dan 80 bit acak baru yang diambil dari generator bilangan acak kriptografis browser, sehingga tidak ada pengidentifikasi yang dikirim ke atau diambil dari server.
- Jumlah ULID menerima bilangan bulat dari 1 hingga 50. Nilai bawaannya adalah 1.
- Hasilkan ULID menghasilkan sekumpulan ULID baru. Mengubah jumlahnya juga menghasilkan sekumpulan ULID baru.
- Salin pada suatu hasil menyalin satu ULID tersebut. Jika lebih dari satu ULID ditampilkan, Salin semua menyalin seluruh daftar, satu ULID per baris.
- Atur ulang mengembalikan jumlah ke 1 dan menghasilkan satu ULID baru.
Di bawah hasil, panel Struktur ULID membagi ULID pertama dalam kumpulan menjadi dua bagian: 10 karakter pertama (stempel waktu) dan 16 karakter terakhir (keacakan).
ULID vs UUID
| Fitur | ULID | UUID (versi 4) |
|---|---|---|
| Panjang | 26 karakter | 36 karakter (dengan tanda hubung) |
| Dapat diurutkan berdasarkan waktu pembuatan | Ya | Tidak |
| Encoding | Base32 Crockford | Heksadesimal |
| Memuat stempel waktu | Ya (48 bit) | Tidak |
| Aman untuk URL tanpa perlu escape | Ya | Ya |
Kedua format bertujuan menghasilkan pengidentifikasi yang unik di berbagai sistem tanpa otoritas pusat yang membagikan nomor. Perbedaan praktis utamanya adalah pengurutan: karena ULID diawali stempel waktu, pengurutan ULID sebagai teks biasa juga mengurutkannya berdasarkan waktu. UUID acak tidak memiliki sifat ini karena setiap bagiannya bersifat acak.
Kegunaan Umum
- Kunci utama basis data: ULID memungkinkan basis data mengindeks baris baru kira-kira dalam urutan penyisipannya, yang ditangani banyak mesin basis data dengan lebih efisien daripada kunci yang sepenuhnya acak.
- Sistem terdistribusi: server yang terpisah dapat menghasilkan ULID secara independen tanpa berkoordinasi dengan penghitung pusat, dan hasilnya masih hampir pasti unik.
- Log peristiwa: karena ULID terurut berdasarkan waktu, daftar ID peristiwa dapat berfungsi sebagai linimasa kasar.
- Pengidentifikasi API dan berkas: format tetap sepanjang 26 karakter yang aman untuk URL bekerja dengan baik dalam alamat web dan nama berkas.
Format pengidentifikasi terkait mencakup KSUID, yang juga mengenkode stempel waktu untuk pengurutan, serta ID Snowflake, yang digunakan oleh Twitter dan lainnya dan menggabungkan stempel waktu, pengidentifikasi mesin, serta penghitung.
Contoh Kode
Setiap contoh di bawah membentuk ULID dengan cara yang sama seperti dijelaskan dalam spesifikasi ULID: enkode stempel waktu 48 bit menjadi 10 karakter Base32 Crockford, enkode 80 bit keacakan menjadi 16 karakter tambahan, lalu gabungkan keduanya.
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}
41Pertanyaan yang sering diajukan
Untuk apa ULID digunakan? ULID digunakan sebagai pengidentifikasi unik untuk baris basis data, sumber daya API, atau peristiwa yang dicatat, ketika pengurutan berdasarkan waktu pembuatan juga bermanfaat.
Berapa panjang ULID? ULID selalu memiliki panjang 26 karakter: 10 karakter untuk stempel waktu dan 16 karakter untuk bagian acak.
Pengenkodean apa yang digunakan ULID? ULID menggunakan alfabet Base32 Crockford, yang terdiri dari digit 0–9 dan huruf A-Z dengan I, L, O, serta U dihapus untuk menghindari kerancuan dengan karakter lain.
Apa perbedaan ULID dari UUID? ULID terurut berdasarkan waktu pembuatan dan memiliki panjang 26 karakter. UUID acak (versi 4) tidak terurut berdasarkan waktu dan memiliki panjang 36 karakter termasuk tanda hubung.
Seberapa besar kemungkinan terjadi benturan antara dua ULID? 80 bit keacakan membuat benturan sangat kecil kemungkinannya. Diperlukan pembuatan sekitar 1,3 triliun ULID dalam milidetik yang sama untuk mencapai peluang 50% bahwa dua ULID mana pun akan sama.
Bisakah ULID dibuat tanpa koneksi internet? Ya. ULID hanya memerlukan jam lokal dan generator bilangan acak, sehingga dapat dibuat sepenuhnya secara luring.
Referensi
- "ULID Specification." GitHub, https://github.com/ulid/spec.
- "Crockford's Base32 Encoding." http://www.crockford.com/base32.html.