Google PDE: Elaborazione di Flussi con Dataflow e Apache Beam — Guida allo studio
Fa parte della Google Professional Data Engineer — Guida allo studio. Esercitati con risposte verificate nel centro esami Google, oppure fai test cronometrati su ExamRoll.io.
Panoramica
L’elaborazione di flussi di dati su Google Cloud si basa sul modello di programmazione unificato di Apache Beam, eseguito dal runner Dataflow. Beam fornisce un’astrazione logica — pipeline di trasformazioni (transform) su PCollection — che disaccoppia il codice dai dettagli di esecuzione come parallelismo, scalabilità automatica (autoscaling) e tolleranza ai guasti (fault tolerance). Nello streaming, la correttezza dipende dalla semantica temporale (tempo dell’evento vs tempo di elaborazione), dalle finestre (fisse, a scorrimento, di sessione, globali), dai watermark, dai trigger e dalla gestione dei dati in ritardo. L’eccellenza operativa su Dataflow richiede il corretto dimensionamento dei worker, la giusta policy di autoscaling, la scelta dello streaming engine e dello shuffle, la progettazione di sink idempotenti, la gestione dei messaggi non recapitabili (dead-letter) e un’osservabilità robusta.
Modello Apache Beam e semantica temporale
Pipeline, transform, PCollection, runner:
- Una pipeline Beam applica un grafo aciclico diretto di PTransform a delle PCollection (limitate o illimitate).
- I runner (Dataflow, Spark, Flink, Direct) eseguono la pipeline; Dataflow fornisce autoscaling gestito, checkpointing e visibilità operativa.
- Le transform includono operazioni per singolo elemento (ParDo), raggruppamento e combinazione (GroupByKey, Combine), join (CoGroupByKey) e I/O (PubSubIO, BigQueryIO, FileIO).
Finestre (Window):
- Finestre fisse (Fixed window): intervalli di tempo non sovrapposti (es. finestre a cascata o “tumbling” di 1 minuto) per aggregazioni periodiche.
- Finestre a scorrimento (Sliding window): finestre sovrapposte per metriche continue (es. finestre di 5 minuti che scorrono ogni minuto).
- Finestre di sessione (Session window): finestre dinamiche che si chiudono dopo un intervallo di inattività, ideali per sessioni utente o picchi di attività di un dispositivo.
- Finestra globale (Global window): la vista predefinita non suddivisa in finestre dell’intero stream illimitato; spesso abbinata a trigger per la materializzazione periodica.
Tempo dell’evento vs tempo di elaborazione:
- Tempo dell’evento (Event time): quando l’evento si è verificato alla fonte; consente aggregazioni logicamente coerenti nonostante le latenze di trasporto variabili.
- Tempo di elaborazione (Processing time): quando l’evento viene osservato dalla pipeline; utile per trigger operativi ma non per la correttezza semantica.
Watermark:
- Un watermark stima la completezza rispetto al tempo dell’evento (l’ipotesi del runner di aver visto tutti gli eventi fino a un tempo T).
- I watermark possono avanzare in modo irregolare o bloccarsi in caso di backpressure o ritardi alla fonte; i dati in ritardo (late data) sono tutti quelli che arrivano con un timestamp inferiore al watermark.
Trigger e dati in ritardo (lateness):
- Predefinito: trigger AfterWatermark che si attiva quando il watermark supera la fine della finestra; con un ritardo consentito (allowed lateness) pari a 0, i dati in ritardo vengono scartati.
- Attivazioni anticipate (early firing), basate sul tempo di elaborazione o sul conteggio, forniscono risultati preliminari a bassa latenza.
- Attivazioni tardive (late firing) consentono correzioni quando arrivano dati in ritardo; la modalità di accumulazione (accumulation mode) determina se i “pane” (risultati parziali) accumulano i risultati o scartano l’output precedente.
- Scegliere il ritardo consentito (allowed lateness) in base alla tolleranza del business e ai compromessi tra storage e calcolo; un ritardo maggiore aumenta la conservazione dello stato e i costi.
Elaborazione stateful, timer, suddivisione in sessioni e deduplicazione:
- Le DoFn stateful mantengono uno stato per chiave (es. ultimo evento visto, aggregazioni parziali) e impostano timer per emettere o cancellare lo stato.
- La suddivisione in sessioni (sessionization) si esprime naturalmente tramite le SessionWindow; per logiche personalizzate, usare uno stato per chiave (keyed state) e timer basati sul tempo di elaborazione o sul tempo dell’evento.
- Deduplicazione: usare un ID stabile per ogni evento e applicare Distinct/Combine per finestra, oppure uno stato per chiave (es. un filtro di Bloom o un set con TTL). Valutare il compromesso tra memoria e falsi positivi rispetto all’accuratezza assoluta.
Modalità di fallimento e compromessi:
- L’uso di finestre basate sul tempo di elaborazione per le metriche di business causa scostamenti (drift) in caso di picchi o tentativi ripetuti (retry); preferire finestre basate sul tempo dell’evento.
- Finestre troppo piccole con trigger anticipati frequenti causano un’emissione eccessiva di “pane” e un’amplificazione delle scritture sul sink (write amplification).
- Un ritardo consentito illimitato può gonfiare lo stato; limitare sempre il TTL dello stato e impostare timer per cancellare le chiavi inattive.
Gestione di Dataflow per carichi di lavoro di streaming
Dimensionamento e scalabilità automatica dei worker:
- La scalabilità automatica orizzontale aggiunge/rimuove worker in base a backlog, ritardo della watermark, CPU e throughput; impostare un valore
maxWorkersragionevole per assorbire i picchi. - Scegliere i tipi di macchina in base ai colli di bottiglia: legati alla CPU (più vCPU), legati alla memoria (tipi ad alta memoria), legati alla rete (VM più grandi riducono l’overhead dello shuffle).
- Aumentare il disco di avvio per shuffle pesanti o sink basati su file. Monitorare il
system lage ibacklog seconds.
- La scalabilità automatica orizzontale aggiunge/rimuove worker in base a backlog, ritardo della watermark, CPU e throughput; impostare un valore
Streaming Engine e shuffle:
- Lo Streaming Engine esternalizza lo stato e lo shuffle nel backend del servizio, migliorando l’elasticità, riducendo la pressione sulla memoria dei worker e abilitando aggiornamenti più rapidi.
- Per fasi con carichi batch pesanti o raggruppamenti di chiavi massivi, usare Dataflow Shuffle per scaricare l’I/O dello shuffle dai worker. Entrambi riducono i fallimenti dei “hot worker” e il “disk thrash” (sovraccarico del disco).
Backpressure, hot key e skew (asimmetria):
- Dataflow gestisce la backpressure tramite il ribilanciamento dinamico del lavoro; tuttavia, ottimizzare il controllo di flusso della sorgente (es. messaggi/byte in sospeso di Pub/Sub) quando applicabile.
- Le hot key (es. ID popolari) creano “straggler” (worker lenti). Mitigare con il partizionamento della chiave (key#N), pre-aggregazione parziale seguita da ri-assegnazione della chiave, o approssimazioni basate su sketch.
- Lo skew (asimmetria) causato da record anomali (payload enormi) o da publisher con picchi di attività può richiedere partizioni per publisher, batching o compressione.
Integrazione con Pub/Sub:
- Usare i topic di Pub/Sub per l’ingestion; abilitare gli attributi dei messaggi per i metadati (es. deviceId, timestamp dell’evento).
- Eseguire l’ingestion con PubSubIO; estrarre i timestamp degli eventi dagli attributi o dal payload, altrimenti usare il tempo di pubblicazione come fallback.
- Le ordering key forniscono un ordinamento per chiave; Dataflow richiede comunque un comportamento idempotente a valle a causa della consegna “at-least-once” (almeno una volta).
Pattern per lo streaming verso BigQuery:
- Preferire BigQueryIO con la Storage Write API per ottenere alta velocità di trasmissione, bassa latenza e semantica “exactly-once” (esattamente una volta) all’interno di uno stream, tramite offset di stream e tentativi automatici.
- Per pipeline semplici a basso rate, gli streaming insert sono accettabili; impostare l’insertId per deduplicare i tentativi del client.
- Le query sui buffer di streaming sono “eventually consistent”; per analisi critiche in termini di tempo, eseguire la query dopo un ritardo del buffer (es. attendere ~2 volte la latenza di disponibilità osservata), o materializzare tramite finestre di micro-batch e la modalità “committed” della Storage Write API.
Effetti “exactly-once”, idempotenza, riesecuzione e sink:
- Beam garantisce un’elaborazione “at-least-once”; l’“exactly-once” deve essere ottenuto a livello del sink usando scritture idempotenti, transazioni o chiavi di deduplicazione.
- BigQuery: usare gli stream di default o i “committed streams” della Storage Write API per l’exactly-once all’interno di uno stream; con gli streaming insert, impostare un insertId stabile.
- File: scrivere file temporanei con nomi univoci, finalizzarli al completamento della finestra e garantire rinominazioni atomiche; evitare la sovrascrittura per prevenire duplicati parziali.
- Database esterni: usare operazioni di “upsert” basate su un ID stabile o implementare finestre di deduplicazione.
- Progettare per la riesecuzione (replay): mantenere trasformazioni deterministiche; assicurarsi che i sink deduplichino in caso di nuovo tentativo.
Gestione dei messaggi non recapitabili (dead-letter), instradamento degli errori, osservabilità:
- Includere le operazioni rischiose di parsing/arricchimento in un blocco try/catch all’interno di un ParDo ed emettere i fallimenti in una PCollection di dead-letter tramite un TupleTag; includere payload, codice di errore e contesto.
- Instradare le DLQ (code di messaggi non recapitabili) verso BigQuery o Cloud Storage per l’analisi; considerare un topic Pub/Sub separato per la rielaborazione.
- Osservabilità: usare le metriche dei job di Dataflow (ritardo della watermark, system lag, throughput), contatori personalizzati, metriche di distribuzione e log per passo in Cloud Logging. Creare allarmi sul ritardo e sul tasso di errore in Cloud Monitoring. Usare Error Reporting per aggregare le eccezioni.
Pattern per l’ottimizzazione delle prestazioni:
- Leggere in modo efficiente: per sorgenti BigQuery, preferire la Storage Read API o letture basate su query che selezionino solo i campi e i filtri necessari.
- Combine lifting: usare i combiner per ridurre il volume dello shuffle prima di un GroupByKey.
- Side input: mettere in cache in memoria i dati di riferimento di piccole dimensioni; prestare attenzione al fanout e alla cadenza di aggiornamento.
- Serializzazione: usare schemi compatti (Avro/Proto) ed evitare un parsing JSON eccessivo nei percorsi critici (“hot path”).
Strategie di deployment, template e aggiornamento
Flex Templates:
- Impacchettano le pipeline in template containerizzati e parametrizzati per deployment riproducibili. I Flex Templates supportano dipendenze personalizzate, immagini GPU e isolamento dell’ambiente.
- Esternalizzare i parametri di runtime (es. sottoscrizione di input, tabella di output, sink per i messaggi non recapitabili, maxWorkers) per abilitare deployment specifici per ogni ambiente.
Aggiornamenti e compatibilità delle pipeline:
- Dataflow supporta l’aggiornamento in-place per molte pipeline di streaming se i nomi delle trasformazioni, le specifiche di stato e i tipi di output rimangono compatibili. Utilizzare nomi stabili per le PTransform.
- Per modifiche incompatibili al grafo o allo stato, eseguire un cutover controllato: avviare il nuovo job, quindi eseguire il drain del vecchio job per terminare il lavoro in corso (in-flight) e smettere di leggere nuovi elementi.
Drain e snapshot:
- Il drain completa l’elaborazione in modo controllato (gracefully), scrive l’output rimanente e termina; va coordinato con la retention di Pub/Sub o con gli snapshot per evitare perdite di dati (gap).
- Per garantire la continuità, è possibile creare uno snapshot di Pub/Sub, avviare la nuova pipeline posizionandosi (seek) sullo snapshot o su un timestamp appropriato, verificare l’output, quindi eseguire il drain del vecchio job.
Esempi di configurazione:
- Esempio di windowing con trigger anticipati/tardivi e accumulazione:
undefined
- Esempio di BigQueryIO con la Storage Write API:
undefined
- Errori comuni:
- Scrivere su sink basati su file in modalità streaming senza scritture finestrate (windowed) può bloccare la finalizzazione; abilitare le scritture finestrate e i trigger.
- Crescita illimitata: dimenticare di limitare lo stato o la latenza consentita (allowed lateness) può causare perdite di memoria (memory leak) e fallimenti di scalabilità.
- Timestamp mancanti: non assegnare timestamp agli eventi fa sì che la pipeline utilizzi di default il tempo di elaborazione (processing time), perdendo correttezza in presenza di ritardi variabili.
Scenario di un problema pratico
NovaTrack Inc. ingerisce telemetria IoT globale da 50.000 sensori di temperatura e deve fornire aggregati a livello di minuto, persistere i dati grezzi e popolare una dashboard in tempo reale. Sono previsti messaggi malformati occasionali e consegne fuori ordine. La soluzione deve scalare automaticamente, rendere disponibili i record errati per l’ispezione e supportare aggiornamenti senza downtime.
Approccio:
Ingestion e semantica temporale
- Creare un topic Pub/Sub regionale e publisher per regione con gli attributi deviceId e eventTs (RFC3339). Abilitare le chiavi di ordinamento (ordering keys) per deviceId quando possibile.
- Motivazione: Pub/Sub fornisce un punto di ingresso (ingress) durevole ed elastico con consegna at-least-once. Associare i timestamp degli eventi al punto di origine (at the edge) preserva il tempo effettivo dell’evento (event time); l’ordinamento per dispositivo riduce il riordinamento all’interno dello stesso dispositivo senza creare colli di bottiglia centrali.
Pipeline di streaming Dataflow con finestre basate sull’event-time
- Leggere da una sottoscrizione dedicata tramite PubSubIO, estraendo eventTs come timestamp di Beam, utilizzando come fallback il
publishTimese mancante. - Applicare FixedWindows di 1 minuto con un trigger anticipato (early) a 30 secondi e attivazioni tardive (late) per ogni elemento in ritardo; impostare una latenza consentita (allowed lateness) di 10 minuti e l’accumulo dei riquadri (pane).
- Motivazione: Le finestre basate sull’event-time assicurano aggregati al minuto accurati; le attivazioni anticipate alimentano la dashboard con una freschezza dei dati inferiore al minuto; le attivazioni tardive correggono gli aggregati man mano che arrivano i dati in ritardo. Il limite alla latenza (lateness bound) limita la dimensione dello stato e i costi.
- Leggere da una sottoscrizione dedicata tramite PubSubIO, estraendo eventTs come timestamp di Beam, utilizzando come fallback il
Validazione, arricchimento e routing dei messaggi non recapitabili (dead-letter)
- Implementare un ParDo che esegue il parsing del JSON, valida lo schema e gli intervalli, e arricchisce i dati con piccole informazioni di riferimento statiche tramite un side input caricato da BigQuery all’avvio del job.
- Usare TupleTags per emettere i record validi nell’output principale e gli errori in una PCollection dead-letter contenente payload, errore, deviceId e timestamp del parsing; scrivere la DLQ in una tabella BigQuery partizionata.
- Motivazione: I side input mantengono i dati di riferimento in memoria per una bassa latenza. La cattura dei messaggi non recapitabili consente l’ispezione e la rielaborazione mirata delle righe errate senza bloccare il flusso principale.
Aggregazione e mitigazione degli hot key
- Raggruppare per deviceId e calcolare avg/min/max per minuto con CombineFns. Per le metriche regionali top-N, partizionare (shard) per regione#N per evitare hot key, quindi ri-aggregare.
- Motivazione: I Combiner minimizzano il volume di dati dello shuffle e i costi; lo sharding delle chiavi previene colli di bottiglia su una singola chiave durante il fan-in regionale.
Sink ed effetti exactly-once
- Scrivere gli eventi grezzi validati e gli aggregati al minuto su BigQuery usando BigQueryIO con la Storage Write API. Impostare un ID di inserimento stabile basato su deviceId + eventTs per garantire l’idempotenza in caso di tentativi di riesecuzione personalizzati (retry).
- Motivazione: La Storage Write API fornisce un’ingestion ad alta velocità (throughput) e bassa latenza con semantica exactly-once all’interno di uno stream. Gli ID stabili assicurano la deduplicazione a valle (downstream) in caso di riesecuzioni (replay).
Strategia di coerenza per la dashboard
- La dashboard interroga le tabelle aggregate partizionate con un intervallo di visualizzazione (lookback) di 2 minuti rispetto al watermark o un ritardo fisso di 2 volte la latenza di disponibilità osservata per i dati in streaming.
- Motivazione: La visibilità dello streaming in BigQuery è eventually consistent; posticipare leggermente le letture evita di perdere righe in transito (in-flight) pur mantenendo un comportamento quasi in tempo reale.
Operazioni: autoscaling e Streaming Engine
- Abilitare lo Streaming Engine; impostare maxWorkers in base al picco previsto (es. 3 volte la media), selezionare un tipo di macchina dimensionato per operazioni di parsing e crittografia legate alla CPU (CPU-bound), e aumentare il disco di avvio per ospitare i dati di shuffle transitori.
- Monitorare il ritardo del watermark (lag), i secondi di backlog, la CPU e il throughput per passo; impostare alert su ritardi prolungati e picchi nel tasso di messaggi DLQ.
- Motivazione: Lo Streaming Engine esternalizza lo stato e lo shuffle per una maggiore elasticità e aggiornamenti più semplici; un corretto dimensionamento e monitoraggio prevengono violazioni silenziose degli SLO.
Deployment e aggiornamenti con i Flex Templates
- Impacchettare la pipeline come un Flex Template con parametri: sottoscrizione di input, tabelle di output, tabella DLQ, maxWorkers e regione. In caso di una modifica incompatibile, avviare la nuova pipeline sullo stesso topic con una nuova sottoscrizione, verificare gli output, quindi eseguire il drain del vecchio job. Opzionalmente, creare uno snapshot di Pub/Sub e posizionare la nuova sottoscrizione sullo snapshot per garantire zero perdite di dati.
- Motivazione: I Flex Templates abilitano deployment ripetibili e parametrizzati. Un cutover blue/green verificato con drain garantisce zero perdita di dati e un downtime minimo.
Rielaborazione e backfill batch
- Archiviare file Avro compressi degli eventi grezzi in Cloud Storage tramite un output secondario; eseguire una pipeline Dataflow batch per eseguire il backfill o rielaborare i dati in BigQuery quando i modelli o gli schemi cambiano.
- Motivazione: Archivi durevoli dei dati grezzi supportano la riproducibilità e l’evoluzione dello schema senza impattare il percorso critico (hot path).
Questo design produce aggregati corretti a bassa latenza con costi limitati, un chiaro isolamento degli errori, forte osservabilità e percorsi di aggiornamento sicuri, gestendo al contempo dati fuori ordine e in ritardo su scala globale.
← Analisi con BigQuery e Ingegneria del Data Warehouse · Tutti i domini · Messaggistica →
Esercitati su queste domande → · Pratica cronometrata su ExamRoll.io →
Pass the whole exam — not just this question
You found this answer. Get every verified question and explanation in one place, and save hours of prep. Free to start.
Supera l'esame →