El diseño de sistemas de bases de datos distribuidas a escala de hyperscaler se reduce fundamentalmente a la gestión de trade-offs entre la amplificación de lectura, escritura y espacio (RUM conjecture), y la superación de cuellos de botella en la latencia P99. En un entorno donde los costos de almacenamiento y la disponibilidad de object storage son atractivos, pero su latencia es significativamente mayor que la de NVMe local, la ingeniería se enfoca en cómo mitigar estas desventajas a través de estructuras de datos, algoritmos y patrones de acceso.

La relevancia de este problema se ha intensificado con la creciente demanda de aplicaciones de baja latencia y el auge de cargas de trabajo intensivas en datos, como las bases de datos vectoriales. La evolución de la infraestructura de la nube ha empujado a los arquitectos a repensar cómo los principios clásicos de bases de datos se aplican a una jerarquía de almacenamiento que incluye NVMe, SSDs y object storage, cada uno con características de rendimiento y costo muy distintas. La clave es identificar el cuello de botella dominante para una carga de trabajo específica y aplicar una solución quirúrgica que, inevitablemente, introduce nuevos trade-offs.

Arquitectura del Sistema

Los sistemas analizados emplean diversas arquitecturas para optimizar la latencia P99. SlateDB, una librería LSM-tree, extiende el concepto de LSM a object storage como S3, GCS y R2. Esto implica batching de escrituras en archivos inmutables y el uso de caching local (NVMe) para mitigar la latencia de lecturas frías de object storage, donde un cache miss puede costar 20-30 ms frente a 150 µs de NVMe. ScyllaDB, por su parte, introduce Logstor, un motor de almacenamiento opt-in para cargas de trabajo intensivas en lectura. Logstor utiliza un índice en memoria (hash + ubicación en flash) para permitir lecturas de un solo I/O de disco, evitando la búsqueda compleja de SSTables, Bloom Filters y estructuras de datos indexadas de un LSM-tree tradicional. Esto se logra a expensas de un mayor uso de RAM y una mayor amplificación de escritura debido a la escritura de valores completos en cada actualización.

Valkey aborda el escalado vertical y horizontal. Para el escalado vertical, utiliza lockless queues para desacoplar I/O de red y parsing de comandos de la ejecución de comandos, que permanece single-threaded. Esto permite que los hilos de I/O permanezcan activos mientras el hilo principal ejecuta comandos, mejorando el throughput. Para el escalado horizontal, Valkey 9.0 implementa atomic slot migration, donde el shard de origen transmite un snapshot y cambios incrementales al target, transfiriendo la propiedad solo cuando el target se pone al día, permitiendo abortar migraciones fallidas sin pérdida de datos. Turbopuffer, para bases de datos vectoriales a escala de 100B vectores, utiliza object storage como respaldo duradero y caches locales de SSD para datos calientes. Emplea hierarchical clustering y RaBitQ binary quantization para reducir el tamaño del índice, permitiendo un filtrado inicial rápido antes de re-rankear un subconjunto con vectores de precisión completa. Finalmente, TigerBeetle, una base de datos de transacciones financieras, implementa 'diagonal scaling' manteniendo datos calientes en NVMe y datos fríos en object storage. Para interactuar con object storage, construyó un cliente multi-cloud propio en Zig, utilizando io_uring y zero-copy sends, evitando las latencias y dependencias de los SDKs oficiales, logrando mejoras significativas en throughput de PUT/GET.

Flujo de Lectura en Logstor (ScyllaDB)

  1. 1 Solicitud de Lectura Cliente solicita un valor para una clave.
  2. 2 Búsqueda en Índice RAM El índice en memoria busca el hash de la clave y la ubicación del registro en...
  3. 3 Cache Hit Si el valor está en cache, se devuelve inmediatamente.
  4. 4 Disk I/O (Cache Miss) Si no está en cache, se realiza una única operación de I/O a disco para obten...
  5. 5 Devolver Valor El valor se devuelve al cliente.

Flujo de Migración Atómica de Slots (Valkey)

  1. 1 Inicio Migración Shard de origen inicia la migración de slots a shard destino.
  2. 2 Snapshot y Stream Origen envía un snapshot inicial y cambios incrementales al destino.
  3. 3 Catch-up Destino aplica los cambios para ponerse al día con el origen.
  4. 4 Transferencia de Propiedad Una vez sincronizado, la propiedad de los slots se transfiere atómicamente.
  5. 5 Finalización Migración completada, destino es el nuevo propietario.
CapaTecnologíaJustificación
storage LSM-tree Mecanismo para balancear read/write amplification, adaptado para object storage. vs B-tree Immutable files, batching de escrituras.
storage Object Storage (S3, GCS, R2) Almacenamiento duradero y de bajo costo para datos fríos o de respaldo. vs Block Storage, Local SSD/NVMe Costo por GET/PUT, latencia de cold reads.
cache NVMe local Cache de alta velocidad para mitigar la latencia de object storage. vs DRAM, SSD SATA Latencia de 150 µs vs 20-30 ms de S3.
storage Logstor (ScyllaDB) Motor de almacenamiento optimizado para cargas de trabajo intensivas en lectura con un índice en memoria. vs LSM-tree tradicional Índice en RAM, una única I/O de disco para lectura, mayor amplificación de escritura.
compute Lockless Queues Desacoplar I/O de red y parsing de comandos de la ejecución de comandos en Valkey para mejorar el escalado vertical. vs Mutexes, Thread pools con locks
orchestration Atomic Slot Migration (Valkey) Mecanismo para el escalado horizontal de clusters, permitiendo rebalanceo de datos sin pérdida. vs Replicación completa de shard, Migración con downtime Transferencia de snapshot y deltas, handoff atómico.
data-processing RaBitQ binary quantization Reducción del tamaño del índice para bases de datos vectoriales, permitiendo un filtrado rápido. vs Cuantización escalar, PCA Un bit por dimensión para el índice sombra.
networking Custom Object Storage Client (TigerBeetle) Cliente de alto rendimiento para object storage, optimizado para baja latencia y alto throughput. vs AWS C++ SDK, GCP SDK Implementado en Zig, usa io_uring, zero-copy sends, custom DNS/TLS/HTTP.

Trade-offs

Ganancias
  • ▲ Latencia P99.9 (Logstor)
  • ▲▲ Throughput (Valkey)
  • ▲▲ Velocidad de Upload a S3 (TigerBeetle)
  • ▲ Velocidad de Download de S3 (TigerBeetle)
  • ▲ Recall (Turbopuffer)
Costes
  • ▲ Uso de RAM (Logstor)
  • ▲ Amplificación de Escritura (Logstor)
  • ▲ Complejidad de Implementación (TigerBeetle)
  • ▲ Intensidad Aritmética (Turbopuffer)

Fundamentos Teóricos

El concepto de trade-offs en el diseño de almacenamiento de bases de datos se formaliza en la 'RUM Conjecture' (Read, Update, Memory/Space), que postula que es difícil optimizar simultáneamente la amplificación de lectura, la amplificación de escritura y la amplificación de espacio. Esta conjetura es una extensión de los principios observados en estructuras de datos como los Log-Structured Merge-trees (LSM-trees), introducidos por Patrick O'Neil, Edward Cheng, Dieter Gawlick y Elizabeth O'Neil en su paper de 1996 'The Log-Structured Merge-Tree (LSM-Tree)'.

Los LSM-trees fueron diseñados para optimizar las escrituras en discos rotacionales, donde las escrituras secuenciales son mucho más rápidas que las aleatorias. La adaptación de los LSM-trees a object storage, como se ve en SlateDB, es una aplicación moderna de estos principios, donde la inmutabilidad de los archivos y la capacidad de batching de escrituras se alinean bien con las características de object storage, a pesar de su mayor latencia. La optimización de Valkey para el escalado vertical y horizontal resuena con los principios de diseño de sistemas distribuidos que buscan maximizar la eficiencia de los recursos y la disponibilidad, a menudo haciendo referencia a los principios de consistencia y disponibilidad explorados en el teorema CAP.