lección 2
Día 1 — Architecture Review: diseñar streaming
Evalúas 4 opciones de streaming, escribes un ADR completo con trade-offs y lo defiendes ante Clara en el Architecture Review Board.
⏱ 45 min
### Martes, 9:15 AM — La pizarra de Alberto
Alberto te lleva a la sala Turing. La pizarra está llena de diagramas a medio borrar de la sesión anterior. Coge un rotulador azul y dibuja el pipeline actual: un DAG de Airflow ("txn_daily_load") que a las 4:00 AM extrae las transacciones del día anterior desde el topic de Kafka hacia S3 raw, las transforma con PySpark en EMR (limpieza + enriquecimiento + deduplicación) y las carga en Redshift gold. Latencia end-to-end: entre 4 y 28 horas dependiendo de si el job falla y hay que relanzarlo manualmente.
Alberto subraya dos números en rojo: "<5 min" y "<15 min". "El negocio necesita dos cosas", dice mientras golpea la pizarra. "Primera: fraude en menos de 5 minutos. El modelo de Miguel necesita features frescas — si tienen más de 5 minutos, la precisión baja del 92% al 67%. Con los 2.357 fraudes reales que detectamos al mes, eso son casi 600 fraudes que se nos escapan, unos 1,9 millones de euros. Segunda: alertas regulatorias en menos de 15 minutos. El Banco de España nos exige notificación inmediata de transacciones sospechosas por encima de 10.000 euros. Inmediata significa menos de 15 minutos, no al día siguiente."
1Alberto Reyes (pizarra, rotulador rojo):2"No me traigas la solución. Tráeme 3 opciones con trade-offs3claros, coste de cada una, y tu recomendación justificada. Si no4puedes defender tu decisión ante Clara en 5 minutos, no está lista.56El ADR debe estar escrito ANTES del Architecture Review del jueves.7Clara lo va a leer. Si tiene preguntas que no puedes responder,8te manda de vuelta. Y el jueves es el jueves -- no hay segunda9oportunidad esta semana."
Alberto establece las reglas del ADR
### Evaluación de opciones
Te sientas en tu escritorio con un café doble y abres un documento en blanco. Necesitas evaluar las opciones viables para consumir del topic transactions.completed de Kafka MSK y reducir la latencia de horas a minutos. Después de investigar 2 horas, identificas 4 candidatos serios:
- 01.Spark Structured Streaming (EMR): Aprovechar la infraestructura existente de Spark. Micro-batch cada 30s-1min. Soporta watermarks para late data, aggregations con ventanas, y exactly-once con checkpoints en S3. El equipo ya conoce PySpark.
- 02.Kafka Connect + S3 Sink: Conector managed que escribe directamente de Kafka a S3. Simple de configurar, bajo mantenimiento. Pero sin transformación inline — necesitaría un paso adicional de procesamiento (Lambda o segundo job).
- 03.Consumer Group nativo (Python con confluent-kafka): Escribir un consumer con la librería de Confluent. Máximo control, mínima latencia (<10s). Pero máximo mantenimiento: gestión manual de offsets, errores, escalado, rebalanceo de particiones.
- 04.Amazon Kinesis Data Analytics (Flink managed): Servicio 100% managed de AWS para stream processing. Cero operación, auto-scaling. Pero coste alto, lock-in fuerte con AWS, y el equipo no conoce Flink SQL.
Analizas cada opción contra 5 criterios que Alberto siempre usa: latencia alcanzable, complejidad operativa, coste mensual estimado, integración con el stack existente, y escalabilidad a 10x volumen actual (preparación para Black Friday y campañas de Navidad).
1# Evaluación cuantitativa de las 4 opciones2# Criterios ponderados según prioridades de NeoBank34opciones = {5 "Spark Structured Streaming": {6 "latencia_seg": 45, # Micro-batch cada 30s + processing7 "complejidad_ops": 3, # Media (ya tenemos EMR)8 "coste_mensual_eur": 800, # Cluster EMR siempre encendido9 "integración": 5, # Perfecto: ya usamos PySpark10 "escalabilidad_10x": 4, # Auto-scaling de executors11 "exactly_once": True, # Checkpoints en S312 "equipo_conoce": True, # 8 jobs batch existentes13 },14 "Kafka Connect S3 Sink": {15 "latencia_seg": 180, # flush.size + rotate.interval16 "complejidad_ops": 2, # Baja (managed connector)17 "coste_mensual_eur": 400, # Solo connector + S318 "integración": 3, # Necesita pasó adicional19 "escalabilidad_10x": 3, # Limitado por flush config20 "exactly_once": False, # At-least-once nativo21 "equipo_conoce": False, # Nadie ha usado Connect22 },23 "Consumer Python nativo": {24 "latencia_seg": 8, # Procesamiento inmediato25 "complejidad_ops": 5, # Alta (todo manual)26 "coste_mensual_eur": 300, # ECS Fargate27 "integración": 4, # Python, compatible28 "escalabilidad_10x": 2, # Manual, frágil29 "exactly_once": False, # Requiere implementación manual30 "equipo_conoce": True, # Python sí, pero no a este nivel31 },32 "Kinesis Data Analytics": {33 "latencia_seg": 45, # Similar a Spark micro-batch34 "complejidad_ops": 1, # Zero ops (managed)35 "coste_mensual_eur": 1500, # KPU pricing es caro36 "integración": 2, # Flink SQL != PySpark37 "escalabilidad_10x": 5, # Auto-scaling nativo38 "exactly_once": True, # Built-in39 "equipo_conoce": False, # Nadie conoce Flink40 },41}4243# Pesos de cada criterio (según prioridades de Alberto/Clara)44pesos = {45 "latencia": 0.25, # SLA es crítico46 "complejidad": 0.20, # Menos ops = más tiempo para features47 "coste": 0.15, # Presupuesto limitado pero no bloqueante48 "integración": 0.25, # Reutilizar stack reduce riesgo49 "escalabilidad": 0.15, # Importante pero a medio plazo50}5152print("╔══════════════════════════════════════════════════════════════╗")53print("║ EVALUACIÓN DE OPCIONES -- STREAMING NEOBANK ║")54print("╠══════════════════════════════════════════════════════════════╣")55for nombre, datos in opciones.items():56 cumple_sla = datos["latencia_seg"] < 300 # 5 min = 300 seg57 print(f"║ {nombre:35s} ║")58 print(f"║ Latencia: {datos['latencia_seg']:>3}s | Coste: {datos['coste_mensual_eur']:>4} EUR/mes ║")59 print(f"║ Exactly-once: {'Sí' if datos['exactly_once'] else 'No':2s} | SLA: {'✓ CUMPLE' if cumple_sla else '✗ FALLA'} ║")60 print(f"║ Equipo conoce: {'Sí' if datos['equipo_conoce'] else 'No'} ║")61 print("╠══════════════════════════════════════════════════════════════╣")62print("║ RECOMENDACIÓN: Spark Structured Streaming ║")63print("╚══════════════════════════════════════════════════════════════╝")
Evaluación cuantitativa de las 4 opciones de streaming
### El ADR — Architecture Decision Record
Con la evaluación clara, escribes el ADR. Alberto tiene un template estándar que todo el equipo usa — basado en el formato de Michael Nygard pero adaptado a NeoBank con una sección de "Impacto regulatorio" que no existe en ADRs estándar.
1# ADR-007: Migración a Near-Real-Time para Pipeline de Transacciones23## Estado4Propuesto (pendiente aprobación ARB 2024-09-19)56## Contexto7El pipeline batch actual (Airflow DAG "txn_daily_load") procesa8transacciones con latencia de 4-28h. Los SLAs de negocio exigen:9- Modelo de fraude: features con frescura <5 min (impacto: 1.9M EUR/mes)10- Alertas regulatorias BdE: notificación de txns >10K EUR en <15 min11- Feature store: alimentar 5 features para scoring de fraude1213Topic Kafka: transactions.completed14Volumen actual: ~4.5M eventos/día (~52 eventos/seg, picos 200/s)15Formato: Avro con Schema Registry (schema v3.2)16Retención Kafka: 7 días1718## Opciones evaluadas1920La comparación de las 4 opciones frente a los criterios clave está21en la tabla siguiente (la columna elegida aparece resaltada).
ADR-007 (parte 1): estado, contexto y opciones sobre la mesa
### Qué es exactly-once y por qué en banca no es opcional
Antes de seguir, conviene tener claro qué significa la fila de «exactly-once» de la tabla, porque es la que decide la comparación.
Cuando un sistema lee eventos de una cola y algo falla a mitad — se cae el proceso, se corta la red, el clúster se reinicia — hay tres comportamientos posibles al recuperarse:
- At-most-once: procesa cada evento como mucho una vez. Si falla, ese evento se pierde. Rápido y sin duplicados, pero pierde datos. En banca, inaceptable.
- At-least-once: no pierde nada, pero al recuperarse puede volver a procesar lo que ya había procesado. Es lo que da Kafka Connect por defecto. En un almacén de métricas se tolera; aquí significa que una transferencia puede aparecer dos veces.
- Exactly-once: cada evento acaba reflejado una vez y solo una, pase lo que pase.
Lo que hay que entender es que exactly-once no es magia: es una contabilidad. Spark guarda en el checkpointLocation qué offsets de Kafka ha procesado y qué ficheros ha escrito, y lo hace de forma que las dos cosas se confirman juntas o no se confirma ninguna. Al reiniciar, lee ese registro y sabe exactamente por dónde iba. Por eso el checkpointLocation no es un detalle de configuración: es la garantía. Si lo borras, o lo apuntas a otro sitio, o dos jobs comparten el mismo, el exactly-once desaparece sin que nadie avise.
Exactly-once cubre el camino dentro del pipeline. Si tu job, además de escribir en S3, llama a una API que envía una notificación, esa llamada no entra en la contabilidad. Al reprocesar, la notificación se manda dos veces. Eso es exactamente lo que va a pasar el viernes de madrugada, así que apúntalo.
1### Opciones descartadas y justificación23**Kafka Connect S3 Sink:** Cumple SLA de latencia marginalmente (1-3 min)4pero no permite transformación inline. Necesitaríamos un segundo pasó5(Lambda o Spark batch) para enriquecer y calcular features, lo que añade6complejidad y latencia. Descartado por arquitectura fragmentada.78**Consumer Python nativo:** Latencia mínima pero escalabilidad manual y9fragilidad operativa. Con 4.5M eventos/día y picos de 200/s, un solo10consumer no basta. Gestionar consumer groups, rebalanceo y exactly-once11en Python es un proyecto en sí mismo. Descartado por riesgo operativo.1213**Kinesis Data Analytics:** Técnicamente viable pero 1.500 EUR/mes para14un volumen que Spark maneja por 800 EUR. Además, el equipo no conoce15Flink SQL y la migración de lógica PySpark a Flink tiene coste oculto16significativo. Descartado por coste + lock-in + curva de aprendizaje.1718## Decisión19**Spark Structured Streaming en EMR** con micro-batch de 30 segundos.2021## Justificación221. Ya tenemos EMR y 8 jobs PySpark batch -- el equipo conoce la API232. Exactly-once garantizado con checkpoints en S3 (crítico en banca)243. Watermarks nativos para manejar late data (txns que llegan tarde)254. Escala horizontalmente añadiendo executors (auto-scaling configurado)265. Micro-batch de 30s cumple SLA de 5 min con margen de 6x276. Reutiliza schemas Avro + lógica de transformación existente2829## Impacto regulatorio30- Mejora cumplimiento de notificación al BdE (de 24h a <1 min)31- Datos financieros permanecen encriptados en tránsito (TLS 1.3)32- Checkpoints en S3 proporcionan audit trail de procesamiento33- Sara (DPO) válida que no hay impacto en retención de datos personales3435## Consecuencias36- [+] Latencia baja a ~45s (cumple ambos SLAs con margen)37- [+] Features de fraude frescas -> modelo recupera 92% precisión38- [-] Cluster EMR siempre encendido (~800 EUR/mes adicionales)39- [-] Equipo debe dominar Structured Streaming (formación 1-2 semanas)40- [-] Necesitamos definir estrategia de checkpoint y recovery41- [~] Pipeline batch se mantiene como fallback durante 2 sprints4243## Métricas de éxito44- Latencia p95 < 60 segundos (medida en Datadog)45- Zero data loss durante 30 días consecutivos46- Consumer lag promedio < 1.000 eventos47- Features de fraude con freshness < 2 minutos4849## Autor y fecha50- Autor: [Data Engineer]51- Fecha: 2024-09-1752- Revisores: Alberto Reyes, Paula García
ADR-007 (parte 2): opciones descartadas, decisión final y métricas de éxito
Un ADR (Architecture Decision Record) no es burocracia — es la memoria del equipo. Dentro de 6 meses, cuando alguien pregunte "¿por qué usamos Spark y no Kinesis?", el ADR responde sin necesidad de reuniones arqueológicas. Alberto dice: "Si la decisión cuesta más de 2 días revertir, merece un ADR. Si cuesta más de 2 semanas, merece un ADR Y una prueba de concepto."
### El Architecture Review — defendiendo ante Clara
Jueves, 10:00 AM. Sala Grace Hopper. Clara Mendoza preside. Están Alberto, Sara, Miguel, Paula y tú. Clara tiene el ADR impreso con anotaciones en rojo. "Tienes 10 minutos para presentar y 5 para preguntas. Empieza."
Presentas: contexto, opciones, decisión, justificación. Clara interrumpe dos veces:
1Clara Mendoza (ARB, minuto 4):2"Pregunta 1: Si el cluster EMR se cae a las 3AM, ¿cuál es el3Recovery Time Objective? ¿Cuántos minutos perdemos?"45Tu respuesta:6"Los checkpoints en S3 guardan el estado cada micro-batch (30s).7Si el cluster cae, EMR auto-restart lo levanta en ~3 minutos.8El job retoma desde el último checkpoint -- RTO efectivo de93-5 minutos. Zero data loss porque Kafka retiene 7 días."1011Clara Mendoza (minuto 7):12"Pregunta 2: Black Friday. El año pasado tuvimos 10x el volumen13normal durante 72 horas. ¿Qué pasa con tu pipeline?"1415Tu respuesta:16"EMR tiene auto-scaling configurado en Terraform. Puede pasar17de 4 a 12 executors en 4 minutos basándose en consumer lag.18He validado con los números: a 10x volumen (520 eventos/seg),19con 12 executors el micro-batch completa en 24 segundos.20Margen suficiente dentro del trigger de 30 segundos."2122Clara (asiente):23"Aprobado. Siguiente tema."
Architecture Review: las preguntas de Clara y tus respuestas preparadas
Cuando presentes un ADR ante un VP o arquitecto senior, prepara respuestas para las "preguntas asesinas": ¿Qué pasa si se cae? ¿Qué pasa a 10x escala? ¿Cuál es el plan B? ¿Cuánto cuesta si nos equivocamos? Si no puedes responder alguna, di "no lo he evaluado, lo investigo y actualizo el ADR mañana". NUNCA inventes una respuesta.
### Los imprevistos del día
Mientras preparas el ADR (martes por la tarde), recibes dos interrupciones que son completamente normales en un equipo real:
1# Slack DM de Miguel Ortiz -- 14:322Miguel Ortiz:3"Ey, he visto que estás montando el streaming. Necesito que4incluyas el cálculo de features en la misma pipeline --5txn_count_1h, avg_amount_1h y ratio vs histórico. Si las6calculas en streaming me ahorras una consulta a Redis que7tarda 200ms por predicción. Son 52 predicciones/segundo,8200ms cada una... haz la cuenta."910Tú:11"Entendido. Lo tengo en el plan como tarea separada del día 3.12¿Puedes pasarme la spec exacta de las 5 features que necesitas?13Nombres, ventanas temporales, y cómo las consume tu modelo."1415Miguel Ortiz:16"Te mando el doc ahora. Gracias por no decirme 'ya veremos' 👍"
Interrupción de Miguel — legítima pero hay que priorizarla
1# Email de Sara Vidal -- 16:02 (con copia a legal@neobank.es)2Asunto: URGENTE - Solicitud de supresión RGPD - acc_000284733---4Equipo de datos,56El cliente Jenaro Portero Llorente (acc_00028473) ejerció su derecho7de supresión según el artículo 17 del RGPD el pasado 7 de8septiembre de 2024. El plazo legal es de 30 días naturales.910Fecha límite: 7 de octubre de 2024.11Hoy es 18 de septiembre. Quedan 19 días naturales (13 laborables).1213Necesito confirmación ESCRITA de que el equipo de datos puede14completar la supresión/anonimización irreversible en todos los15sistemas antes de la fecha límite.1617Por favor, agendad una reunión conmigo mañana a primera hora18para evaluar el alcance.1920Un saludo,21Sara Vidal22DPO - NeoBank23---
Email de Sara — deadline regulatorio no negociable
En un equipo real, SIEMPRE hay interrupciones. Un día nunca es "una sola tarea". La habilidad no es evitar las interrupciones sino gestionarlas: registrar la petición, confirmar que la has recibido, dar un timeline realista, y seguir con tu prioridad actual. Miguel no es molesto — es un compañero con una necesidad legítima. Sara no es un obstáculo — es la persona que protege a la empresa de multas millonarias.
Regístrate para guardar tu progreso.