Ulid

ULID

Un ULID (Universally Unique Lexicographically Sortable Identifier) es un identificador único diseñado para ser tanto globalmente único como lexicográficamente ordenado. Fue introducido como una alternativa a los UUID (Universally Unique Identifier), con la ventaja adicional de ser más legible y adecuado para sistemas que necesitan ordenación temporal.

Estructura de un ULID

Un ULID tiene una longitud fija de 26 caracteres alfanuméricos y está formado por dos partes:

  1. Timestamp (48 bits):
    • Representa un tiempo en milisegundos desde el Unix epoch (1 de enero de 1970).
    • Se almacena como los primeros 10 caracteres en el formato base32 (alfabeto Crockford).
    • Esto permite que los ULID sean lexicográficamente ordenados por tiempo.
  2. Randomness (80 bits):
    • Consiste en 16 caracteres generados aleatoriamente también en base32.
    • Garantiza que los ULID sean únicos incluso cuando se generan múltiples en el mismo milisegundo.

Características principales

  1. Orden lexicográfico:
    • Gracias a la parte de tiempo, los ULID se ordenan naturalmente por momento de creación.
    • Esto es útil para sistemas donde el orden cronológico es importante, como bases de datos o logs.
  2. Legibilidad:
    • Al usar base32, los ULID evitan caracteres ambiguos como “I” y “l” (i mayúscula y ele minúscula) o “O” y “0” (O mayúscula y cero), lo que facilita su lectura.
  3. Compatibilidad con UUID:
    • Aunque tienen un formato distinto, se pueden usar como reemplazo en la mayoría de los sistemas que soportan UUID.

Ejemplo de ULID

Un ULID típico podría verse así:

01H8K72J27T9A2P03C1P5X3VYV
  • Los primeros 10 caracteres (01H8K72J27) representan el tiempo.
  • Los últimos 16 caracteres (T9A2P03C1P5X3VYV) son la parte aleatoria.

Ventajas sobre UUID

  • Ordenación natural por tiempo.
  • Más legible debido al uso de base32.
  • Más corto (26 caracteres frente a 36 en un UUID en su representación estándar).

La razón por la cual sabemos que los primeros 10 caracteres de un ULID representan el timestamp y los siguientes 16 son aleatorios proviene de la especificación formal de los ULIDs y del desglose técnico de cómo están construidos. Aquí está la explicación en detalle:


Especificación Técnica de ULID

Un ULID está compuesto de 128 bits (16 bytes), divididos en dos partes:

  1. 48 bits para el Timestamp:
    • Los 48 bits (6 bytes) iniciales representan el tiempo en milisegundos desde el Unix epoch.
    • Al codificar estos 48 bits en base32, se generan exactamente 10 caracteres alfanuméricos.
  2. 80 bits para la Aleatoriedad:
    • Los 80 bits restantes (10 bytes) son generados aleatoriamente.
    • Cuando se codifican en base32, estos bits producen 16 caracteres alfanuméricos.

Cálculo Detallado

  1. Timestamp (48 bits):

    • 48 bits = 248, lo que permite representar hasta 281.5 billones de milisegundos desde el Unix epoch.

      2482^{48}

    • Esto cubre un rango de tiempo suficiente (aproximadamente hasta el año 10889).

    • Los 48 bits se dividen en grupos de 5 bits (porque base32 usa bloques de 5 bits por carácter), resultando en 48÷5=9.6, que se redondea a 10 caracteres.

      48÷5=9.648 \div 5 = 9.6

  2. Aleatoriedad (80 bits):

    • 80 bits = 280, lo que da un espacio masivo para generar valores únicos incluso si varios ULIDs se crean en el mismo milisegundo.

      2802^{80}

    • Al dividir 80 bits en bloques de 5 bits, obtenemos 80÷5=16, lo que resulta en 16 caracteres.

      80÷5=1680 \div 5 = 16


Ejemplo Visual de la Estructura

Tomemos este ULID como ejemplo:

01H8K72J27T9A2P03C1P5X3VYV
  1. Primera parte (10 caracteres):

    01H8K72J27

    Esto representa el timestamp. Estos caracteres corresponden a los primeros 48 bits que indican el tiempo de creación.

  2. Segunda parte (16 caracteres):

    T9A2P03C1P5X3VYV

    Esta es la parte aleatoria, generada para garantizar unicidad en un mismo milisegundo.