📖 Disponible en: Español | English
| Equipo |
|---|
| Federico Genaro |
| Santiago Sevitz |
| Maximo Utrera |
Documentos de arquitectura:
Este proyecto presenta el diseño de un sistema distribuido tolerante a fallos para el análisis de datos de ventas de una cadena de cafeterías en Malasia. Fue desarrollado como Trabajo Práctico de la materia Sistemas Distribuidos I (FIUBA) y prioriza escalabilidad, robustez y procesamiento distribuido por pipelines.
El sistema permite procesar grandes volúmenes de transacciones enviadas por un cliente, aplicar transformaciones y agregaciones complejas, y devolver reportes consolidados, manteniendo consistencia incluso ante fallas parciales o catastroficas del sistema.
- Procesar datasets de transacciones de gran tamaño de forma distribuida.
- Soportar múltiples requisitos analíticos (filtrado, agregación, ranking, joins).
- Garantizar tolerancia a fallos, manejo de duplicados e idempotencia.
- Escalado horizontal e independientemente para cada tipo de nodo.
El sistema trabaja principalmente con:
- Transactions (múltiples archivos)
- Transaction Items (múltiples archivos)
Como datos de referencia (para joins):
- Menu Items
- Stores
- Users
Otros datasets (Vouchers, Payment Methods) no se utilizan por no ser necesarios para los resultados esperados.
-
Client: envía datos y recibe reportes.
-
Gateway: punto de entrada al sistema y única interfaz con el cliente.
-
Controller: coordina la ejecución y controla el fin de transmisión.
-
Workers:
- Filter
- GroupBy
- Reducer
- Aggregator
- Joiner
-
Middleware: RabbitMQ como Message-Oriented Middleware.
La comunicación interna se realiza exclusivamente mediante colas de mensajes, permitiendo desacoplamiento y paralelismo.
El sistema utiliza el modelo Worker-per-filter, donde cada etapa del pipeline está aislada:
- Filter: aplica criterios temporales y de negocio.
- GroupBy: agrupa registros por claves relevantes.
- Reducer: ejecuta sumatorias o conteos.
- Aggregator: consolida batches y aplica rankings (Top N).
- Joiner: vincula datos procesados con datasets de referencia.
Cada requisito funcional define un pipeline específico combinando estas etapas.
- El cliente solicita una tarea al Gateway.
- El Controller inicializa la sequencia de control del cliente.
- El cliente envía datasets de referencia.
- El cliente envía batches de transacciones.
- Los workers procesan los datos de forma encadenada.
- El Aggregator consolida resultados.
- El Joiner genera el reporte final.
- El Gateway devuelve el reporte al cliente.
-
Health Check (Egg of Life): monitoreo por heartbeats UDP y reinicio automático de nodos.
-
ACKs diferidos: reencolado de mensajes ante fallos durante procesamiento.
-
Persistencia en disco:
- Joiner: datasets de referencia.
- Aggregator: batches procesados.
- Controller: estado de clientes.
-
Manejo de duplicados: números de secuencia para los paquetes por cliente.
-
Mensajes idempotentes: especialmente para el fin de transmisión.
- Gateway (Se balancea la carga aleatoriamente)
- Controller (Se balancea la carga definiendo deterministicamente el Controller por cliente utilizando una funcion de hash)
- Aggregator
Se implementó el algoritmo Bully para formar una red de monitoreo entre los Egg of life, de manera de garantizar que el sistema no dependa de un solo nodo para reinicios automaticos, sino que estos se reinicien entre si en caso de falla. Con la premisa de un mantainability bajo esta solucion permitira nunca quedar sin este tipo de nodos, y de esta forma poder recuperarse de un caso de caida extrema del sistema (e.g. todos los workers, los gateways, los controllers y los egg of life excepto uno).
- RabbitMQ con colas persistentes.
- Workers desplegados como contenedores Docker.
- Escalado horizontal mediante réplicas.
- Orquestación con Docker Compose (en este caso, pero se puede desplegar en Kubernetes).
- Lenguajes: Go, Python
- Mensajería: RabbitMQ
- Serialización: Protobuf
- Contenedores: Docker
- Dataset: Kaggle – Coffee Shop Transactions
