“Hoy día, muchas aplicaciones hacen un uso intensivo de datos, en lugar de uno intensivo de cálculo. La potencia bruta de la CPU rara vez es un factor limitante para estas aplicaciones: los problemas más importantes suelen estribar en la cantidad de datos, su complejidad y la velocidad a la que cambian.”
Kleppmann, Martin. Designing Data-intensive Applications. O’Reilly, 2017.
En la era de la información, la capacidad de gestionar eficientemente grandes volúmenes de datos se ha convertido en un desafío fundamental para las organizaciones de todos los tamaños. Con el crecimiento exponencial de datos generados por usuarios, dispositivos y sistemas, las aplicaciones modernas se enfrentan a la tarea monumental de no solo capturar estos datos, sino también de procesarlos y almacenarlos de manera eficiente.
Y es precisamente en la eficiencia donde se halla el reto. Las aplicaciones que necesitan realizar operaciones de agregación sobre estos datos enfrentan dificultades significativas que van desde el rendimiento hasta los costos operativos.
La constante escritura de datos en la base de datos principal (en adelante, base de datos fría) puede generar una sobrecarga en el sistema y comprometer el rendimiento de las consultas, impactando negativamente en la experiencia del usuario.
Desafíos en la Gestión de Datos Masivos
En este artículo, analizamos los principales desafíos que presenta la ingesta, tratamiento y provisión de datos masivos en aplicaciones que dependen de un flujo continuo de información. Los aspectos más críticos son:
- Correctitud de los datos: El sistema debe proporcionar información confiable y precisa para que la funcionalidad no se degrade con el tiempo.
- Eficiencia: La escritura constante de datos puede generar costos operativos significativos, tanto en almacenamiento como en procesamiento. El objetivo es reducir estos costos manteniendo la operación correcta.
- Escalabilidad: A medida que aumenta el tráfico y, por lo tanto, el volumen de los datos, el sistema debe ser resiliente y tolerar un mayor flujo de información.
- Rendimiento: Un alto volumen de datos puede impactar negativamente en las consultas, por lo que debe ser un requerimiento clave al diseñar el sistema.
Ejemplo Práctico: Monitoreo de Servidores en Tiempo Real
Pongamos como ejemplo una aplicación que recopila y analiza datos de actividad de servidores en tiempo real para detectar anomalías y garantizar la disponibilidad de los servicios.
Escenario de Datos
- Número de servidores: 100
- Frecuencia de muestreo: 1 minuto
- Número de peticiones por servidor por minuto: 10,000
- Tamaño promedio de cada petición: 1 KB
Esto resulta en 1 millón de peticiones por minuto, lo que equivale a:
- 1 GB/min → 60 GB/h → 1.440 GB/día → 43.2 TB/mes
Al final del día, la aplicación debe proporcionar agregados como:
- Latencia media
- Cantidad total de errores por código HTTP (400, 404, 500…)
- Número total de peticiones recibidas (tráfico total)
Problemas de Rendimiento
Este tipo de sistema, que gestiona registros en tiempo real y realiza cálculos agregados, enfrentará problemas de rendimiento, costos y eficiencia. La base de datos no será capaz de gestionar de manera eficiente tal volumen de escritura y lectura.
Solución: Implementación de Bases de Datos Fría y Caliente
En un primer enfoque, para poder calcular los agregados de datos diarios, almacenaríamos las peticiones que estamos rastreando en nuestra base de datos, y, cuando se solicitase, haríamos el cálculo de los agregados para poder servirlo a un cliente mediante la API. Esta solución podría funcionar hasta cierto punto. Sin embargo, con un alto volumen de datos, el acceso a datos para realizar este cálculo empieza a ser lento, muy lento, y puede llegar a degradar el sistema entero, formando cuellos de botella que irán a peor conforme aumente dicho volumen de datos.
Para solucionar este problema, se puede implementar un sistema intermedio que se apoye en el alto rendimiento de un servicio de caché en memoria, la base de datos caliente.
Ahora, el alto volumen de tráfico será reservado directamente en la base de datos caliente, la caché, que se encargará de realizar los cálculos rápidos de agregados y los irá almacenando conforme van llegando. Esta operación es tremendamente rápida y eficiente y, además, la base de datos en frío no sufre ningún cuello de botella. Independientemente de la caché, otro servicio se encargará, una vez al día, de persistir los agregados (que ya estarán pre-calculados porque se han ido acumulando en la caché), ahora sí, en la base de datos fría.
Frecuencia de Persistencia
La frecuencia de persistencia de los agregados en la base de datos fría depende de nuestras necesidades de negocio. En el ejemplo que estamos tratando, estamos gestionando un historial de agregados de cada día, pero podrían ser de cada semana, cada mes, o incluso de cada hora. En cualquier caso, el objetivo es reducir tanto como se pueda el número de “toques” a la base de datos fría, ya que, cuando estamos haciendo un uso intensivo de los datos, buscamos diseños de alto rendimiento. Cada consulta a la base de datos fría debemos considerarla muy cara en términos de eficiencia y escalabilidad, y, por lo tanto, solo debemos hacer las estrictamente necesarias.
Por tanto, el nuevo diseño incluyendo la nueva base de datos en caliente que actúa de intermediario para gestionar de forma mucho más rápida ese alto volumen de datos sería el siguiente:
Conclusión: Elementos Clave del Nuevo Diseño
En resumen, el diseño de la solución se vuelve algo más complejo que el anterior, pero mucho más eficiente, escalable y elimina esos cuellos de botella en el acceso a datos. Al nuevo diseño le sumamos nuevos elementos para poder implementarlo:
- Un servicio de persistencia en base de datos fría (HotToCold). Este servicio es el encargado de ejecutar, normalmente un job o tarea programada, que toma los datos en caliente y los persiste definitivamente en la base de datos fría. Como se comentó anteriormente, la frecuencia de persistencia dependerá directamente de los requerimientos.
- Una base de datos caliente (Caché).
- Un servicio de consumo del tráfico (Consumer). Este servicio podría ser la propia API de la aplicación, pero es mejor separarlos porque, de esta forma, la API y el servicio de consumo escalan de forma independiente, lo que nos permite asimilar volúmenes aún mayores de tráfico sin que la aplicación se vea afectada. También, esta estrategia en términos de infraestructura y costes es más conveniente; no tendremos que escalar verticalmente la API solo por las necesidades de un único servicio.
Enlaces de interés
- Caso de éxito real aquí.


