La lezione 34 si è chiusa con un elenco delle cose che Hadoop aveva azzeccato e di quelle che aveva sbagliato. La più pesante delle cose sbagliate era lo stato intermedio scritto pesantemente su disco: ogni shuffle finiva sul disco, ogni iterazione di un job iterativo pagava di nuovo la disk tax, e i workload di machine learning e graph giravano ordini di grandezza più lenti di quanto avrebbero dovuto. Il sostituto di MapReduce è uscito dall’AMPLab di UC Berkeley nel 2010, è stato generalizzato in un paper del 2012, è diventato un Apache top-level project nel 2013, e nel 2018 si era già mangiato quasi tutto il mercato del batch processing che Hadoop possedeva. Questa lezione attraversa Spark, l’ecosistema che gli sta intorno, gli engine che gli fanno concorrenza in nicchie diverse, e il decision tree su quando scegliere quale.
L’inquadratura della lezione è comparativa. Spark è uno dei tanti tool di batch a cui un data engineer del 2026 potrebbe aggrapparsi, e la domanda interessante non è quasi mai “Spark è buono?” ma “Spark è il tool giusto per questa specifica forma di lavoro?”. La risposta dipende dalla dimensione dei dati, dal budget di latenza, dalla piattaforma che il team già usa, e dal fatto che il SQL su un warehouse gestito copra già il caso d’uso.
Perché Spark ha vinto
Matei Zaharia e il gruppo dell’AMPLab hanno introdotto Spark per sistemare le specifiche debolezze di MapReduce, mantenendo le parti che funzionavano. Il paper originale (“Resilient Distributed Datasets: A Fault-Tolerant Abstraction for In-Memory Cluster Computing”, NSDI 2012) vale la lettura; le idee di base sono brevi.
Stato intermedio in-memory. Un job Spark rappresenta i dati come una serie di dataset immutabili e partizionati chiamati RDD (Resilient Distributed Datasets). Le operazioni costruiscono un nuovo RDD a partire da uno vecchio. Il punto cruciale è che gli RDD intermedi possono essere messi in cache in memoria attraverso il cluster e riusati dagli stage successivi senza fare un round-trip su disco. Per un job iterativo come addestrare una logistic regression sugli stessi dati di training per cinquanta epoche, MapReduce pagava il costo del disco cinquanta volte; Spark lo paga una volta sola. Gli speedup riportati nel paper del 2012 erano da dieci a cento volte per i workload iterativi, e hanno tenuto in produzione.
Esecuzione DAG-aware. MapReduce eseguiva una coppia map-reduce alla volta, materializzando l’output su HDFS tra un job e l’altro. Una query che richiedeva tre passate di map-reduce era costituita da tre job separati con tre scritture su HDFS. Spark costruisce un directed acyclic graph di tutte le operazioni dentro un singolo job, ottimizza sull’intero grafo, e materializza solo il risultato finale. Il cost model sceglie shuffle boundary migliori, e il runtime può fare pipelining delle operazioni che non richiedono uno shuffle tra di loro.
API migliori. La prima API di Spark era una API funzionale Scala-native, che era già un passo avanti rispetto al raw Hadoop. La seconda erano i DataFrame (2015), modellati su R e pandas, con sotto un query optimiser (Catalyst) che compilava le operazioni sui DataFrame in execution plan efficienti. La terza è stata Spark SQL, che ti permetteva di scrivere una select contro un DataFrame come se fosse una tabella di database. Nel 2020 la maggior parte del codice Spark era DataFrame o SQL, con gli RDD raw riservati ai rari casi in cui le API di livello più alto non andavano bene. PySpark ha reso le stesse API disponibili da Python, che è quello che la maggior parte dei data engineer ha effettivamente scritto.
Polyglot dal primo giorno. Scala (il linguaggio nativo), Java, Python (PySpark) e R avevano tutti API di prima classe. SQL è arrivato dopo ma è diventato dominante. Lo stesso engine eseguiva tutti, il che significava che un team misto di ingegneri Scala-e-Python poteva condividere una codebase senza che il linguaggio fosse un confine di integrazione.
La combinazione di velocità, espressività e copertura linguistica è bastata a spodestare MapReduce come default nel giro di pochi anni. I cluster Hadoop non sono spariti dall’oggi al domani; gli hanno installato Spark accanto a MapReduce, poi Spark ha lentamente preso il sopravvento come engine, poi HDFS è stato sostituito da S3, e un giorno non c’era più un grammo di Hadoop in azienda.
L’ecosistema Spark nel 2026
Spark nel 2026 è uno stack di componenti sopra lo stesso execution engine.
Spark SQL e DataFrame. L’API dominante. Quasi tutto il nuovo codice batch viene scritto qui. Il Catalyst optimiser trasforma i logical plan in physical plan, e il Tungsten execution engine genera bytecode efficiente per gli operatori. Per la maggior parte dei team, “scrivere un job Spark” significa scrivere SQL o operazioni DataFrame concatenate e fidarsi dell’optimiser.
Structured Streaming. L’API di streaming di Spark, che condivide lo stesso modello DataFrame e lo stesso engine. La promessa è “lo stesso codice che processa un batch dei dati di ieri può processare lo stream di oggi”, e Spark si avvicina parecchio a mantenerla. Il Modulo 6 copre lo streaming in dettaglio; per ora il fatto rilevante è che Spark è uno degli engine che si contendono quel workload.
MLlib. La libreria di machine learning classico sopra Spark: implementazioni distribuite di regression, clustering, recommendation, gradient-boosted tree. MLlib contava quando i dati di training non stavano su una singola macchina e il deep learning non era l’approccio dominante. Nel 2026 la maggior parte del training ML si è spostata su framework dedicati (PyTorch, JAX, scikit-learn su una singola macchina grossa, o piattaforme specializzate). MLlib viene ancora rilasciato e funziona ancora; raramente è la prima scelta.
GraphX. L’API di graph processing. Esiste. Quasi nessuno la usa. I workload di graph nel 2026 girano per lo più su engine dedicati (Neo4j, JanusGraph, NebulaGraph, le estensioni graph dentro Postgres o DuckDB) o su Spark con una libreria graph attaccata sopra. GraphX è una nota a piè di pagina.
Il senso di elencare i componenti è che “Spark” nei materiali di marketing copre un’impronta ampia, e l’unico pezzo che la maggior parte dei team usa davvero pesantemente è Spark SQL più i DataFrame. Il resto è disponibile, e occasionalmente rilevante.
Databricks
Spark è rimasto un progetto Apache, ma l’azienda nata dall’AMPLab per commercializzarlo (Databricks, fondata nel 2013) è diventata dominante in un modo che nessun backer commerciale di un progetto Apache ha più eguagliato dai primi anni di Cloudera. Databricks gestisce il più grande servizio di managed Spark, vende un prodotto notebook-and-cluster che è di fatto diventato la piattaforma dati di riferimento per molti team enterprise, e ha esteso la piattaforma con aggiunte proprietarie che il progetto Spark open source non ha. Delta Lake (lezione 37) è la più importante di queste, e Unity Catalog (governance), Photon (un query engine vectorised in C++ per Spark SQL), e i prodotti AI/BI sono tutti solo Databricks.
Nel 2026 Databricks è quotata in borsa (IPO completata a fine 2024), è il secondo più grande vendor di piattaforme dati per fatturato dopo Snowflake, ed è la risposta di default a “vogliamo una piattaforma dati basata su Spark senza dover gestire Spark da soli” nell’enterprise. I Spark gestiti concorrenti (AWS EMR, Google Dataproc, Azure Synapse Spark) sono reali ma non hanno spodestato Databricks per le aziende che si sono impegnate su uno stack Spark-centrico.
I concorrenti nel 2026
Spark non è l’unico engine batch, e sempre più spesso non è quello giusto per parecchie forme comuni di lavoro. Il panorama competitivo è la parte davvero interessante della lezione.
DuckDB. Un database analitico in-process, columnar, su singola macchina, scritto in C++. La promessa di DuckDB è che una frazione enorme dei workload “devo macinare un po’ di file Parquet” non ha bisogno di un cluster: un singolo server moderno con cento gigabyte di RAM può masticare centinaia di gigabyte di Parquet su disco in pochi secondi, senza cluster, senza scheduler, senza impronta operativa. DuckDB gira come libreria dentro Python, R, Node, o una CLI; lo importi, lo punti su S3, e scrivi SQL. Per dataset fino a circa un terabyte, DuckDB è spesso più veloce di Spark sulla stessa query, perché non c’è shuffle, non c’è JVM, non c’è coordinamento driver-executor, solo un processo che legge dati columnar con un execution engine vectorised. DuckDB si è mangiato una fetta significativa del workload “small-to-medium analytics” che prima girava su Spark di default.
Polars. Una libreria di DataFrame scritta in Rust, con un’API simile a Pandas. Stessa nicchia di DuckDB ma con una superficie DataFrame piuttosto che SQL, e un profilo di performance simile: vectorised, columnar, single-machine, veloce. Polars e DuckDB sono diventati sostituti molto vicini per molti casi d’uso, e la scelta tra i due è spesso guidata dal fatto che il team preferisca SQL o DataFrame come superficie.
BigQuery, Snowflake, Redshift, Databricks SQL. I warehouse hosted. Come ha coperto la lezione 33, il pattern ELT consiste nel caricare i dati raw nel warehouse e trasformarli con SQL. Per i workload che si infilano in questo pattern (la maggior parte di BI e analytics), l’engine del warehouse gestisce internamente il batch processing, e Spark non è proprio nel quadro. L’utente scrive una select e l’engine del warehouse (Dremel dentro BigQuery, gli engine proprietari dentro Snowflake e Redshift, Photon dentro Databricks SQL) fa il lavoro di batch distribuito in modo invisibile.
Trino e Presto. Engine SQL distribuiti per le query, originariamente sviluppati a Facebook (Presto, 2013) e poi forkati in Trino (2020). Entrambi sono progettati per interrogare dati che stanno su object storage e warehouse senza copiarli. Trino è la scelta open source dominante per “SQL su molte sorgenti”, con Starburst come backer commerciale. Si sovrappone a Spark SQL per le query analitiche ad-hoc e ai warehouse per le letture federate. Raramente è la prima scelta per ETL pesante ma spesso è la risposta giusta per le query interattive degli analyst attraverso un lake.
Dask e Ray. Librerie di distributed computing native Python. Dask è la più vicina nello spirito a Spark: un’API DataFrame e uno scheduler di task, entrambi in Python, che scalano su cluster. Ray è più generale (un framework di task distribuiti) ed è diventato il backend di default per il training e il serving distribuiti di ML. Entrambi hanno una nicchia in cui Python è il linguaggio principale e il workload non si adatta bene a Spark o al SQL del warehouse, ma nessuno dei due ha spodestato Spark per il batch generico.
Quando scegliere Spark nel 2026
Un breve decision tree.
flowchart TD
Q[Batch work to do] --> SizeQ{Data size}
SizeQ -->|"Fits in RAM<br/>on one machine"| Single[DuckDB or Polars]
SizeQ -->|"100GB to a few TB"| MidQ{Already in a<br/>warehouse?}
SizeQ -->|"Many TB to PB"| Spark[Spark or Databricks]
MidQ -->|Yes| WH[Warehouse SQL<br/>BigQuery, Snowflake, Redshift]
MidQ -->|No, on object storage| LakeQ{Need streaming<br/>or complex ETL?}
LakeQ -->|No, just SQL| Trino[Trino or DuckDB on S3]
LakeQ -->|Yes| Spark
Spark --> StreamQ{Sub-second<br/>latency?}
StreamQ -->|Yes| Flink[Flink, see Module 6]
StreamQ -->|No| SparkOK[Spark Structured Streaming<br/>or batch]
Spark si guadagna il suo posto quando una o più delle seguenti condizioni è vera.
I dati sono davvero grandi. Da terabyte a petabyte per job. Gli engine single-machine cominciano ad arrancare, i credit del warehouse diventano cari, e lo shuffle a scala di cluster, che Spark fa bene, diventa il collo di bottiglia. Questo è il workload per cui Spark è stato progettato e quello in cui è ancora il default.
Il job mescola batch e streaming sugli stessi dati. Structured Streaming permette allo stesso code path di servire entrambe le modalità, con un guadagno di efficienza significativo rispetto a far girare due stack separati. Se la tua piattaforma ha bisogno di entrambi e non vuoi gestire Flink per il lato streaming, Spark è una buona risposta.
Sei già su Databricks o hai un cluster Spark. L’inerzia è un tiebreaker legittimo. Se la piattaforma è già in piedi, il team la conosce, e il workload ci sta dentro, “usa quello che hai” è la decisione corretta.
La trasformazione coinvolge cose che il SQL non esprime bene. Uso pesante di UDF, integrazione con librerie ML in Python, operazioni complesse su graph o array: l’API DataFrame di Spark è più espressiva del SQL del warehouse per questi casi.
Quando NON scegliere Spark.
I dati stanno su una singola macchina. Un singolo server da 64 core e 512 GB processa centinaia di gigabyte di Parquet più velocemente di un cluster Spark, con un solo binario e un solo operatore (tu). DuckDB o Polars è la risposta giusta qui. La soglia si sta alzando ogni anno man mano che la RAM costa meno e DuckDB diventa più veloce, e parecchi workload “ci serviva Spark” del 2018 oggi sono workload single-machine.
Il lavoro si può esprimere come SQL su un warehouse gestito. Se i dati sono già in Snowflake o BigQuery e la trasformazione è SQL, l’engine del warehouse è più veloce, più economico, e drammaticamente più semplice da gestire rispetto a tirare su un job Spark per leggere fuori, trasformare, e scrivere indietro. La lezione 33 ha coperto perché questo è il pattern dominante.
Serve latenza real-time, sub-secondo. Spark Structured Streaming ha migliorato sostanzialmente le sue performance a bassa latenza rispetto al modello micro-batch originale, ma Flink resta la scelta dominante per il processing genuinamente evento-per-evento con budget nell’ordine dei millisecondi. Il Modulo 6 attraversa quella decisione in dettaglio.
Cross-link a PySpark
Se stai scegliendo Spark per la tua piattaforma e vuoi imparare l’engine, questo sito ha un corso PySpark dedicato all’indirizzo /programming/courses/pyspark/ che entra più a fondo nell’esperienza concreta di scrivere job: dimensionamento del cluster, partition tuning, comportamento dello shuffle, le strategie di join che l’optimiser sceglie, e i modi in cui i job Spark in produzione vanno male. Questa lezione copre la decisione architetturale; il corso PySpark copre il mestiere quotidiano.
Chiusura della lezione
Spark sta nel mezzo del panorama batch moderno. Non è più il default per i workload piccoli (DuckDB), e non è più il default per i workload con forma da warehouse (Snowflake o BigQuery), ma è ancora il default per il batch genuinamente grande e per il batch-and-streaming unificato sullo stesso engine. L’inquadratura che il resto del Modulo 5 userà è che Spark è uno di tanti engine specializzati, ognuno che si guadagna il suo posto contro le alternative. La lezione 36 si volge alla questione di come i dati vengono disposti sullo storage che sta sotto tutti questi engine: i file format, i table format, e le open-table-format wars che hanno prodotto Delta, Iceberg e Hudi.
Riferimenti e letture di approfondimento
- Matei Zaharia et al., “Resilient Distributed Datasets: A Fault-Tolerant Abstraction for In-Memory Cluster Computing”, NSDI 2012,
https://www.usenix.org/conference/nsdi12/technical-sessions/presentation/zaharia(consultato 2026-05-01). - Apache Spark documentation,
https://spark.apache.org/docs/latest/(consultato 2026-05-01). - Databricks documentation,
https://docs.databricks.com/(consultato 2026-05-01). - DuckDB documentation,
https://duckdb.org/docs/(consultato 2026-05-01). Vale la pena leggere la pagina “Why DuckDB” per le scelte di design. - Polars user guide,
https://docs.pola.rs/(consultato 2026-05-01). - Trino documentation,
https://trino.io/docs/current/(consultato 2026-05-01). - “Spark: The Definitive Guide” (Bill Chambers e Matei Zaharia, O’Reilly, 2018). Leggermente datato ma ancora il riferimento end-to-end più chiaro su Spark.