Langkau ke kandungan

Penjana ULID - Hasilkan ID Unik yang Boleh Disusun Dalam Talian Secara Percuma

Alat penjana ULID percuma yang mencipta pengecam unik, boleh disusun serta-merta. Hasilkan ULID yang selamat dari segi kriptografi untuk pangkalan data, API & sistem teragih dalam talian.

Penjana ULID

Masukkan nilai untuk melihat keputusan
Kalkulator Pemuatan...
📚

Dokumentasi

Apakah ULID?

ULID (Pengecam Boleh Isih Secara Leksikografi yang Unik Sejagat) ialah kod sepanjang 26 aksara yang digunakan untuk melabelkan rekod dalam pangkalan data atau peristiwa dalam sistem teragih. Ia menggabungkan masa semasa dengan data rawak, jadi senarai ULID yang diisih mengikut abjad akhirnya diisih berdasarkan masa setiap satunya dicipta. Penjana ULID ialah alat yang menghasilkan kod ini.

Struktur ULID

ULID mempunyai dua bahagian, ditulis berturutan tanpa pemisah:

  • Cap masa (10 aksara): bilangan milisaat sejak 1 Januari 1970 (zaman Unix), yang meliputi sehingga 48 bit.
  • Rawak (16 aksara): 80 bit data rawak, ditambah supaya dua ULID yang dicipta dalam milisaat yang sama hampir pasti berbeza.

Kedua-dua bahagian ditulis menggunakan abjad Base32 Crockford: digit 0–9 dan huruf A-Z, kecuali huruf I, L, O dan U. Keempat-empat huruf itu tidak disertakan kerana boleh disalah anggap sebagai digit 0 dan 1, atau antara satu sama lain. Hasilnya ialah rentetan pendek yang mudah dibaca dengan lantang dan selamat digunakan terus dalam URL.

Cara Mengira ULID

Penjana ULID membina pengecam dalam tiga langkah.

  1. Baca masa semasa dalam milisaat sejak epok Unix. Ini ialah nombor 48 bit.
  2. Jana 80 bit data rawak, biasanya daripada penjana nombor rawak yang selamat secara kriptografi, menghasilkan 10 bait rawak.
  3. Kodkan kedua-dua bahagian secara berasingan menggunakan abjad Base32 Crockford: cap waktu 48 bit menjadi 10 aksara, manakala nilai rawak 80 bit menjadi 16 aksara. Kedua-dua rentetan yang dikodkan digabungkan untuk menghasilkan ULID akhir sepanjang 26 aksara.

Pengekodan berfungsi dengan membaca nombor 5 bit pada satu masa, kerana setiap aksara Base32 mewakili salah satu daripada 32 nilai yang mungkin (2^5 = 32). Sepuluh aksara boleh memuatkan sehingga 50 bit, yang mencukupi untuk cap waktu 48 bit. Enam belas aksara memuatkan tepat 80 bit, sepadan dengan bahagian kerawakan tanpa baki.

Contoh pengiraan

Andaikan penjana ULID berjalan pada cap waktu 1712345678901 (milisaat sejak epok) dan memperoleh bait rawak [12, 240, 88, 3, 199, 45, 6, 231, 128, 17].

Langkah 1 – kodkan cap waktu. Bahagikan 1712345678901 berulang kali dengan 32, ambil baki setiap kali dan baca digit dari yang terakhir hingga yang pertama (ini ialah penukaran asas standard). Ini menghasilkan rentetan sepanjang 10 aksara, iaitu 01HTQW311N.

Langkah 2 – kodkan kerawakan. Pekkan 10 bait rawak ke dalam aliran 80 bit, kemudian baca 5 bit pada satu masa dan tukarkan setiap bahagian 5 bit kepada aksara Base32. Ini menghasilkan rentetan sepanjang 16 aksara, iaitu 1KR5G0Y75M3EF00H.

Langkah 3 – gabungkan bahagian. ULID akhir ialah:

101HTQW311N 1KR5G0Y75M3EF00H
2

ditulis tanpa ruang: 01HTQW311N1KR5G0Y75M3EF00H, dengan jumlah 26 aksara.

Menggunakan Penjana Ini

Penjana berjalan dalam pelayar. Setiap ULID dibina daripada jam pelayar dan 80 bit rawak baharu yang diambil daripada penjana nombor rawak kriptografi pelayar, jadi tiada pengecam dihantar kepada atau diambil daripada pelayan.

  • Bilangan ULID menerima nombor bulat daripada 1 hingga 50. Nilai lalainya ialah 1.
  • Jana ULID menghasilkan kumpulan baharu. Menukar bilangan itu juga menghasilkan kumpulan baharu.
  • Salin pada satu hasil menyalin ULID tersebut sahaja. Apabila lebih daripada satu dipaparkan, Salin semua menyalin seluruh senarai, satu ULID bagi setiap baris.
  • Tetapkan semula menetapkan bilangan kembali kepada 1 dan menjana satu ULID baharu.

Di bawah hasil, panel Struktur ULID memisahkan ULID pertama dalam kumpulan kepada dua bahagiannya: 10 aksara pertama (cap waktu) dan 16 aksara terakhir (kerawakan).

ULID berbanding UUID

CiriULIDUUID (versi 4)
Panjang26 aksara36 aksara (dengan tanda sempang)
Boleh diisih mengikut masa penciptaanYaTidak
PengekodanBase32 CrockfordHeksadesimal
Mengandungi cap waktuYa (48 bit)Tidak
Selamat digunakan dalam URL tanpa perlu melarikan aksaraYaYa

Kedua-dua format bertujuan menghasilkan pengecam yang unik merentas sistem tanpa pihak berkuasa pusat mengagihkan nombor. Perbezaan praktikal utama ialah pengisihan: kerana ULID bermula dengan cap waktu, mengisih ULID sebagai teks biasa juga mengisihnya mengikut masa. UUID rawak tidak mempunyai sifat ini kerana setiap bahagiannya adalah rawak.

Kegunaan Umum

  • Kunci primer pangkalan data: ULID membolehkan pangkalan data mengindeks baris baharu mengikut urutan anggaran baris itu dimasukkan, yang dikendalikan oleh banyak enjin pangkalan data dengan lebih cekap berbanding kunci yang sepenuhnya rawak.
  • Sistem teragih: pelayan berasingan boleh menjana ULID secara bebas tanpa perlu berkoordinasi dengan kaunter pusat, dan hasilnya masih hampir pasti unik.
  • Log peristiwa: kerana ULID diisih mengikut masa, senarai ID peristiwa juga boleh berfungsi sebagai garis masa anggaran.
  • Pengecam API dan fail: format tetap sepanjang 26 aksara yang selamat untuk URL berfungsi dengan baik dalam alamat web dan nama fail.

Format pengecam berkaitan termasuk KSUID, yang turut mengekod cap waktu untuk pengisihan, dan ID Snowflake, yang digunakan oleh Twitter serta pihak lain dan menggabungkan cap waktu, pengecam mesin serta pembilang.

Contoh Kod

Setiap contoh di bawah membina ULID dengan cara yang sama seperti yang diterangkan dalam spesifikasi ULID: mengekod cap waktu 48 bit sebagai 10 aksara Base32 Crockford, mengekod 80 bit data rawak sebagai 16 aksara lagi, kemudian menggabungkannya.

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());
33

Python

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())
32

Java

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

Soalan lazim

Apakah kegunaan ULID? ULID digunakan sebagai pengecam unik untuk baris pangkalan data, sumber API atau peristiwa yang dilog, dalam keadaan pengisihan mengikut masa penciptaan juga berguna.

Berapakah panjang ULID? ULID sentiasa sepanjang 26 aksara: 10 aksara untuk cap waktu dan 16 untuk bahagian rawak.

Apakah pengekodan yang digunakan oleh ULID? ULID menggunakan abjad Base32 Crockford, yang terdiri daripada digit 0–9 dan huruf A-Z dengan I, L, O serta U dibuang bagi mengelakkan kekeliruan dengan aksara lain.

Apakah perbezaan ULID dengan UUID? ULID diisih mengikut masa penciptaan dan panjangnya ialah 26 aksara. UUID rawak (versi 4) tidak diisih mengikut masa dan panjangnya ialah 36 aksara termasuk tanda sempang.

Sejauh manakah kemungkinan perlanggaran antara dua ULID? 80 bit kerawakan menjadikan perlanggaran amat tidak mungkin. Penjanaan kira-kira 1.3 trilion ULID dalam milisaat yang sama diperlukan untuk mencapai kebarangkalian 50% bahawa mana-mana dua ULID sepadan.

Bolehkah ULID dijana tanpa sambungan internet? Ya. ULID hanya memerlukan jam setempat dan penjana nombor rawak, jadi ia boleh dicipta sepenuhnya di luar talian.

Rujukan

  1. "ULID Specification." GitHub, https://github.com/ulid/spec.
  2. "Crockford's Base32 Encoding." http://www.crockford.com/base32.html.