Al llarg del mòdul hem tractat els esdeveniments com a unitats discretes: una comanda es crea, un pagament es confirma. Però hi ha una classe de problemes en què els esdeveniments arriben de forma contínua i a gran velocitat —clics d'usuaris, lectures de sensors IoT, transaccions de targeta, línies de log— i el valor està a processar-los a mesura que flueixen, sense esperar a acumular-los. Això és el streaming de dades en temps real: tractar les dades com un flux infinit (unbounded) sobre el qual apliquem transformacions, agregacions i detecció de patrons en qüestió de mil·lisegons.

El streaming és la base de casos d'ús com la detecció de frau a l'instant, els quadres de comandament en viu, les recomanacions en temps real o la monitorització de sistemes. En aquesta lliçó entendràs la diferència fonamental entre processament per lots (batch) i per fluxos (streaming), el paper de les finestres temporals, i com Kafka Streams ens permet implementar tot això amb codi relativament senzill.

Contingut

  1. Batch vs Streaming: la diferència fonamental
  2. Conceptes del processament de fluxos
  3. Finestres (windows): agrupar el temps
  4. Kafka Streams: processament sobre Kafka
  5. Exemple: detecció de frau per finestra
  6. Casos d'ús reals
  7. Errors comuns i consells
  8. Exercicis i solucions
  9. Conclusió

  1. Batch vs Streaming: la diferència fonamental

El processament per lots (batch) opera sobre un conjunt de dades finit i complet (per exemple, "totes les vendes d'ahir") en un moment programat. El processament per fluxos (streaming) opera sobre un flux infinit d'esdeveniments a mesura que arriben.

Aspecte Batch Streaming
Dades Finites, acotades Infinites, contínues
Latència Alta (minuts/hores) Baixa (ms/segons)
Quan processa En un moment programat A mesura que arriben els esdeveniments
Visió de les dades Completa Parcial (el vist fins ara)
Exemple Nòmina mensual, informe diari Detecció de frau, alertes en viu
Eines típiques Spark batch, ETL nocturn Kafka Streams, Flink, Spark Streaming

La frase clau: en batch tens totes les dades abans de començar; en streaming mai no les tens totes, perquè sempre en pot arribar una més. Això obliga a raonar d'una altra manera, especialment amb el temps.

  1. Conceptes del processament de fluxos

Abans de programar, fixem el vocabulari:

  • Stream: seqüència infinita d'esdeveniments ordenats (aproximadament) en el temps.
  • Transformacions sense estat (stateless): processen cada esdeveniment de forma independent. Exemples: filter (descartar), map (transformar).
  • Transformacions amb estat (stateful): necessiten recordar informació d'esdeveniments anteriors. Exemples: comptar, sumar, agregar per clau. Requereixen un magatzem d'estat (state store).
  • Temps de l'esdeveniment (event time) vs temps de processament (processing time):
    • Event time: quan va passar l'esdeveniment (marca en el propi missatge).
    • Processing time: quan el processa el sistema.
    • Poden diferir molt (un esdeveniment d'un mòbil sense cobertura pot arribar minuts tard). El processament seriós es basa en event time.
  • Dades tardanes (late data): esdeveniments que arriben després del que s'esperava. El sistema ha de decidir si els incorpora o els descarta.

  1. Finestres (windows): agrupar el temps

Com que el flux és infinit, no podem "sumar-ho tot". En el seu lloc, agrupem els esdeveniments en finestres temporals i calculem sobre cada finestra. Hi ha tres tipus principals:

flowchart TB
    subgraph Tumbling["Tumbling (fixes, sense solapament)"]
        direction LR
        T1["[0-5min]"] --- T2["[5-10min]"] --- T3["[10-15min]"]
    end
    subgraph Hopping["Hopping/Sliding (solapades)"]
        direction LR
        H1["[0-5min]"] --- H2["[2-7min]"] --- H3["[4-9min]"]
    end
    subgraph Session["Session (per activitat)"]
        direction LR
        S1["activitat...gap...nova sessió"]
    end
Tipus de finestra Descripció Cas d'ús
Tumbling (fixa) Intervals fixos sense solapament. Cada esdeveniment cau en una sola finestra "Vendes cada 5 minuts"
Hopping / Sliding (lliscant) Intervals fixos que se solapen (avancen per salts) "Mitjana mòbil dels últims 5 min, actualitzada cada minut"
Session (de sessió) Es tanca després d'un període d'inactivitat (gap) "Activitat d'un usuari fins que deixa d'interactuar"

Exemple: per detectar frau busquem "més de 3 pagaments en 1 minut des de la mateixa targeta". Això és una agregació amb estat sobre una finestra d'1 minut agrupada per targeta.

  1. Kafka Streams: processament sobre Kafka

Kafka Streams és una llibreria Java que consumeix de topics de Kafka, processa les dades (filtratge, agregació, finestres, joins) i escriu els resultats en altres topics. No necessita un clúster a part: és codi que despleguescom una aplicació normal i que escala afegint instàncies.

Conceptes de la seva API:

  • KStream: representa un flux d'esdeveniments (cada registre és un fet independent).
  • KTable: representa una taula d'estat (cada clau té el seu últim valor; els nous registres actualitzen).
  • State store: magatzem local (recolzat a Kafka) on es desen les agregacions amb estat, tolerant a fallades.
# Configuració mínima d'una app Kafka Streams
application.id: detector-fraude        # identifica l'app i els seus state stores
bootstrap.servers: localhost:9092      # clúster de Kafka
default.key.serde: ...StringSerde      # com serialitzar les claus
processing.guarantee: exactly_once_v2  # garantia de processament
  • application.id és crític: identifica l'aplicació i anomena els seus topics interns i state stores. Dues instàncies amb el mateix application.id formen un grup i es reparteixen la feina.
  • processing.guarantee: exactly_once_v2 activa el processament exactly-once dins de Kafka (entre topics), recolzant-se en transaccions.

  1. Exemple: detecció de frau per finestra

Detectem targetes amb més de 3 pagaments en una finestra d'1 minut:

StreamsBuilder builder = new StreamsBuilder();

// 1. Llegim el flux de pagaments del topic d'entrada
KStream<String, Pago> pagos = builder.stream("pagos");

pagos
    // 2. Reagrupem per targeta (la clau passa a ser la targeta)
    .groupBy((clave, pago) -> pago.tarjetaId(),
             Grouped.with(Serdes.String(), pagoSerde))
    // 3. Definim una finestra TUMBLING d'1 minut
    .windowedBy(TimeWindows.ofSizeWithNoGrace(Duration.ofMinutes(1)))
    // 4. Comptem els pagaments per targeta dins de cada finestra
    .count(Materialized.as("conteo-pagos-por-tarjeta"))
    // 5. Convertim la taula de resultats de nou en flux
    .toStream()
    // 6. Ens quedem només amb les que superen el llindar
    .filter((tarjetaVentana, conteo) -> conteo > 3)
    // 7. Emetem una alerta al topic de sortida
    .map((tarjetaVentana, conteo) ->
        KeyValue.pair(tarjetaVentana.key(),
                      new AlertaFraude(tarjetaVentana.key(), conteo)))
    .to("alertas-fraude", Produced.with(Serdes.String(), alertaSerde));

KafkaStreams streams = new KafkaStreams(builder.build(), config);
streams.start();

Explicació pas a pas:

  1. builder.stream("pagos") crea un KStream que llegeix cada pagament del topic d'entrada.
  2. groupBy reagrupa per tarjetaId: ara els esdeveniments de la mateixa targeta comparteixen clau i es processen junts. És la base de qualsevol agregació amb estat.
  3. windowedBy(TimeWindows.ofSize... 1 minut) defineix finestres tumbling d'un minut. withNoGrace significa que no esperem dades tardanes.
  4. count(...) manté, en un state store tolerant a fallades, quants pagaments porta cada targeta a la finestra actual.
  5. toStream() converteix la KTable de recomptes en un flux de canvis per poder continuar processant.
  6. filter(... conteo > 3) deixa passar només les combinacions targeta-finestra que superen el llindar de frau.
  7. map construeix una AlertaFraude i to("alertas-fraude") la publica al topic de sortida, on un altre servei podrà bloquejar la targeta o avisar el client.

El resultat és un detector de frau que reacciona en temps real, sense lots nocturns.

  1. Casos d'ús reals

  • Detecció de frau: patrons anòmals de transaccions a l'instant (com l'exemple).
  • Monitorització i alertes: detectar caigudes de servei o pics d'errors en els logs en viu.
  • Quadres de comandament en temps real: vendes per minut, usuaris actius ara mateix.
  • Recomanacions: ajustar suggeriments segons la navegació actual de l'usuari.
  • IoT i telemetria: agregar lectures de milers de sensors i detectar llindars (temperatura, vibració).
  • Enriquiment d'esdeveniments: unir (join) un flux de comandes amb una taula de clients per afegir dades al vol.

Errors Comuns i Consells

  • Confondre event time amb processing time. Si agregues per processing time, un esdeveniment retardat cau en la finestra equivocada i els resultats són incorrectes. Basa les finestres en el temps de l'esdeveniment sempre que l'ordre importi.
  • Ignorar les dades tardanes. Decideix explícitament la teva política: període de gràcia, descart o reprocessament. No decidir és decidir malament.
  • Oblidar que l'estat creix. Les agregacions amb estat consumeixen memòria/disc. Fes servir finestres amb retenció acotada i neteja l'estat obsolet.
  • Esperar "exactly-once" d'extrem a extrem. Kafka Streams ho garanteix entre topics de Kafka, però en escriure en sistemes externs tornes a necessitar idempotència (lliçó 05-02).
  • Fer servir streaming quan n'hi havia prou amb un batch. Si la latència d'hores és acceptable, un batch és més simple i barat. El streaming afegeix complexitat operativa.
  • Consell: comença amb transformacions sense estat (filter, map); introdueix estat i finestres només quan el cas d'ús ho exigeixi.

Exercicis

  1. Per a cada cas, indica si faries servir batch o streaming i per què: (a) informe comptable de tancament mensual; (b) alerta quan un sensor supera 80 °C; (c) càlcul nocturn de comissions; (d) comptador d'usuaris connectats en directe.
  2. Vols calcular una "mitjana mòbil de temperatura dels últims 10 minuts, actualitzada cada 2 minuts". Quin tipus de finestra faries servir i per què?
  3. Explica amb les teves paraules la diferència entre KStream i KTable i posa un exemple de dada adequada per a cadascun.

Solucions

  1. (a) Batch: dades finites del mes, sense urgència. (b) Streaming: requereix reacció immediata. (c) Batch: procés programat nocturn sobre dades completes. (d) Streaming: mètrica en viu que canvia contínuament.
  2. Una finestra hopping/sliding (lliscant) de mida 10 minuts amb un salt (hop) de 2 minuts. És lliscant perquè les finestres se solapen: cada 2 minuts s'emet un nou resultat que cobreix els últims 10 minuts, que és justament el que demana una mitjana mòbil.
  3. Un KStream modela un flux de fets independents (cada registre és un esdeveniment que se suma als anteriors), per exemple cada pagament o cada clic. Un KTable modela un estat per clau on cada nou registre actualitza el valor anterior d'aquella clau, per exemple el saldo actual de cada compte o l'últim preu de cada producte.

Conclusió

El streaming de dades tracta els esdeveniments com un flux infinit i els processa a mesura que arriben, aconseguint latències de mil·lisegons enfront de les hores del batch. Vam aprendre a raonar sobre el temps (event time vs processing time), a agrupar esdeveniments en finestres (tumbling, lliscants i de sessió) i a implementar agregacions amb estat en Kafka Streams mitjançant un detector de frau real. També vam veure quan convé streaming i quan n'hi ha prou amb un batch més senzill.

Amb aquesta lliçó tanquem el Mòdul 5: Arquitectures Dirigides per Esdeveniments i Missatgeria. Has recorregut el camí complet: des dels fonaments dels esdeveniments i la seva missatgeria asíncrona, passant per l'emmagatzematge amb Event Sourcing i CQRS, la coordinació de transaccions distribuïdes amb el patró Saga, fins al processament de fluxos en temps real. Aquests patrons constitueixen la columna vertebral dels sistemes distribuïts moderns i et preparen per dissenyar arquitectures escalables, resilients i reactives.

Curs d'Arquitectura d'Aplicacions

Mòdul 1: Fonaments de l'Arquitectura d'Aplicacions

Mòdul 2: Principis i Tàctiques de Disseny

Mòdul 3: Estils i Patrons Arquitectònics

Mòdul 4: Arquitectures Distribuïdes i Microserveis

Mòdul 5: Arquitectures Dirigides per Esdeveniments i Missatgeria

Mòdul 6: Disseny Dirigit pel Domini (DDD)

Mòdul 7: Dades i Persistència

Mòdul 8: Arquitectura al Núvol i Desplegament

Mòdul 9: Qualitat, Seguretat i Observabilitat

Mòdul 10: Evolució, Governança i Casos Pràctics

© Copyright 2026. Tots els drets reservats