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 Solicitud de Lectura Cliente solicita un valor para una clave.
- 2 Búsqueda en Índice RAM El índice en memoria busca el hash de la clave y la ubicación del registro en...
- 3 Cache Hit Si el valor está en cache, se devuelve inmediatamente.
- 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 Devolver Valor El valor se devuelve al cliente.
Flujo de Migración Atómica de Slots (Valkey)
- 1 Inicio Migración Shard de origen inicia la migración de slots a shard destino.
- 2 Snapshot y Stream Origen envía un snapshot inicial y cambios incrementales al destino.
- 3 Catch-up Destino aplica los cambios para ponerse al día con el origen.
- 4 Transferencia de Propiedad Una vez sincronizado, la propiedad de los slots se transfiere atómicamente.
- 5 Finalización Migración completada, destino es el nuevo propietario.
| Capa | Tecnología | Justificació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.