El problema fundamental que aborda este artículo es la gestión eficiente del costo y la disponibilidad de grandes volúmenes de datos temporales (TimeSeries) con patrones de acceso heterogéneos. A medida que los datasets crecen a petabytes, mantener todos los datos en almacenamiento de baja latencia se vuelve prohibitivamente caro, mientras que la demanda de retención y acceso ocasional a datos históricos persiste. La solución se centra en la implementación de un tiering de almacenamiento que mueve datos menos accedidos a medios más económicos (object storage como S3) sin comprometer la latencia percibida por el usuario para consultas históricas.
Este desafío no es nuevo; los sistemas de almacenamiento han lidiado con la jerarquía de memoria y el tiering de datos desde los primeros mainframes. La novedad radica en la escala y la necesidad de automatización en un entorno distribuido y dinámico, donde la inmutabilidad de los datos temporales (una vez escritos, no cambian) permite optimizaciones significativas. La evolución desde una solución de streaming genérica (Kafka/Flink) a una integración más profunda con el sistema de base de datos (Cassandra) refleja una maduración en la comprensión de los trade-offs operativos y de costos en sistemas de datos a hiperescala.
Arquitectura del Sistema
La arquitectura inicial de tiering de datos temporales de Netflix se basa en un pipeline de streaming. Los datos se escriben simultáneamente en Cassandra (almacenamiento caliente) y se transmiten a través de Apache Kafka. Desde Kafka, los datos son procesados por Apache Flink, que los hash-particiona por Time Series ID, los agrupa por tiempo de evento y los escribe en S3 como archivos Parquet. Un job de compactación diario de Flink optimiza estos archivos Parquet: crea Row Groups pequeños (4-8 MB), ordena los eventos por tiempo dentro de cada grupo y genera Bloom Filters. Estos metadatos y Bloom Filters se almacenan en EVCache para acelerar la planificación de consultas. Una vez compactados, los datos en Cassandra pueden ser truncados.
La evolución hacia una solución nativa de Cassandra introduce la ReadOnlyCompactionStrategy (ROCS), una estrategia de compactación personalizada que, para Time Slices inmutables, re-compacta todos los SSTables para alinearlos con rangos de token, reduciendo el fan-out de lectura. Los backups de Cassandra en S3, que incluyen un manifiesto declarativo y los SSTables, se utilizan directamente. Cassandra 4.1 permite el uso de Memtables pluggables; en este caso, un 'backupmemtable' personalizado redirige las lecturas de tablas 'frías' directamente a los backups de S3. Este Memtable descarga los componentes de índice y metadatos de los SSTables (excluyendo Data.db) localmente para una planificación eficiente de consultas. Las lecturas de S3 se paralelizan y se benefician de un cache compartido y prefetching. Se optimizan configuraciones como el tamaño de los chunks de compresión, y se deshabilitan read repair y speculative retries para evitar costos y latencias innecesarias en S3. Un control plane de TimeSeries automatiza la transición de las Time Slices entre los estados de almacenamiento caliente y frío, utilizando Virtual Tables de Cassandra para verificar el éxito de la compactación ROCS y la completitud de los backups. Para aislar la carga de lectura de datos fríos, se puede desplegar un clúster de Cassandra secundario, con instancias de hardware más ligeras, que apunte a los mismos backups de S3.
Flujo de Tiering con Kafka/Flink a S3
- 1 TimeSeries Data Plane Escribe datos a Cassandra (hot) y Kafka (stream)
- 2 Apache Kafka Buffer de eventos para procesamiento en streaming
- 3 Apache Flink (Streaming) Hash-particiona, agrupa eventos y escribe Parquet a S3
- 4 Apache Flink (Compaction Job) Optimiza Parquet (Row Groups, ordenamiento, Bloom Filters)
- 5 TimeSeries Control Plane Registra metadatos de archivos compactados, trunca Cassandra
- 6 S3 Almacenamiento de datos fríos optimizados
- 7 TimeSeries Data Plane (Read) Consulta hot y cold tiers, fusiona resultados
Flujo de Tiering Nativo con Cassandra a S3
- 1 TimeSeries Control Plane Marca Time Slice como inmutable
- 2 Cassandra (ROCS) ReadOnlyCompactionStrategy optimiza SSTables por token range
- 3 Cassandra (Backup) Realiza backup de SSTables y manifiesto a S3
- 4 TimeSeries Control Plane Actualiza DDL de tabla con 'backupmemtable' y timestamp
- 5 Cassandra (Backup Memtable Init) Descarga índices y metadatos de SSTables de S3 localmente
- 6 Cassandra (Read) Sirve lecturas directamente desde S3 usando metadatos locales
- 7 S3 Almacenamiento de backups de Cassandra
| Capa | Tecnología | Justificación |
|---|---|---|
| storage | Apache Cassandra | Almacenamiento de datos calientes y base para el tiering frío, con extensiones para leer directamente de S3. vs ScyllaDB, DynamoDB ReadOnlyCompactionStrategy (ROCS), pluggable Memtables ('backupmemtable'), optimizaciones de chunk de compresión y deshabilitación de read repair/speculative retries. |
| storage | Amazon S3 | Almacenamiento de objetos de bajo costo para datos fríos y backups de Cassandra. vs Google Cloud Storage, Azure Blob Storage |
| data-processing | Apache Kafka | Plataforma de streaming de eventos para la solución inicial de tiering a S3. vs Amazon Kinesis, Google Cloud Pub/Sub |
| data-processing | Apache Flink | Motor de procesamiento de streaming para la solución inicial de tiering, encargado de la escritura y compactación de Parquet en S3. vs Apache Spark Streaming, Google Dataflow Tareas dedicadas por bucket, batching de eventos, creación de Row Groups pequeños, ordenamiento de eventos. |
| cache | EVCache | Caché distribuida para almacenar Bloom Filters y metadatos de archivos Parquet, acelerando la planificación de consultas. vs Redis, Memcached |
Trade-offs
Ganancias
- ▲ Reducción de costos de almacenamiento
- ▲ Reducción de la huella de EBS de Cassandra
- ▲ Reducción de la complejidad operativa (solución Cassandra nativa)
- ▲ Mejora de la latencia P90 (solución Cassandra nativa)
Costes
- △ Mayor uso de CPU en Cassandra para lecturas frías desde S3
- ▲ Overhead de infraestructura de streaming (solución Kafka/Flink)
- △ Latencia de lectura más alta comparada con almacenamiento caliente
CREATE TABLE data_20260616_00_04 (
...
PRIMARY KEY ((time_series_id, time_bucket, event_bucket), event_time, event_id, key)
) WITH CLUSTERING ORDER BY (event_time DESC, event_id DESC, key DESC)
...
AND compaction = ...
AND compression = ...
AND memtable = 'backupmemtable:timestamp=1781953200000'
...cqlsh> SELECT * FROM netflix_views.cluster_view
WHERE keyspace_name = 'system_views' AND table_name = 'sstable_tasks';
cqlsh> SELECT * FROM netflix_views.complete_backups
WHERE keyspace_name = 'my_ks' AND table_name = 'my_table';Fundamentos Teóricos
El concepto de tiering de almacenamiento y la gestión de datos con diferentes patrones de acceso se remonta a la jerarquía de memoria en la arquitectura de computadoras, un principio fundamental descrito por Wilkes en los años 60. La idea de mover datos entre diferentes niveles de almacenamiento (cache, RAM, disco, cinta) según su 'calidez' o frecuencia de acceso es una aplicación directa de este principio para optimizar el costo y el rendimiento. En el contexto de bases de datos, la inmutabilidad de los datos temporales, una vez escritos, es clave. Esto se alinea con los principios de los sistemas de solo anexión (append-only) y las estructuras de datos inmutables, que simplifican la concurrencia y la recuperación. La estrategia de compactación ReadOnlyCompactionStrategy (ROCS) y el uso de Bloom Filters para optimizar las lecturas son aplicaciones directas de algoritmos y estructuras de datos bien establecidos en la literatura académica. Los Bloom Filters, introducidos por Burton H. Bloom en 1970, son una técnica probabilística para verificar la pertenencia a un conjunto, reduciendo significativamente las operaciones de I/O al evitar lecturas innecesarias. La gestión de SSTables (Sorted String Tables) y los principios de LSM-trees (Log-Structured Merge-trees), popularizados por papers como "The Log-Structured File System" de Rosenblum y Ousterhout (1992) y su aplicación en bases de datos como LevelDB y RocksDB, son fundamentales para la eficiencia de escritura y compactación en sistemas como Cassandra.