Data building blocks
Spark and shuffles
Spark runs a pipeline as a graph of steps and keeps data in memory where it can. Narrow steps stay on one machine, wide steps need a shuffle, and the shuffle usually decides the cost.
Apache Spark generalizes MapReduce. Instead of two fixed steps, you write a whole pipeline, and Spark turns it into a graph of operators over partitioned data. Intermediate results can stay in memory, so chained steps stop writing to disk after every job. Most of the tuning work comes down to one thing: avoiding expensive shuffles.
Concept
Before you start. A partition is one slice of a data set, processed by one task. A shuffle is a step that moves rows between partitions, usually over the network, so that rows with the same key end up together.
The big idea
Think of a factory line. Most stations work on their own parts. Some stations need parts from everyone, so the parts must travel across the floor first. Those trips are the shuffle, and they are the slow part.
Spark splits the pipeline into stages at each shuffle. Steps inside a stage run together without moving data.
Walking through it
This sketch shows the shape of a typical Spark job. It reads from S3 paths that you would need to replace, so treat it as a sketch.
from pyspark.sql import functions as F
clicks = spark.read.parquet("s3://lake/clicks/date=2026-10-13/")
ads = spark.read.parquet("s3://lake/dim_ads/")
daily = (clicks
.filter(F.col("is_bot") == False) # narrow: no data movement
.join(ads, "ad_id") # wide: shuffle, or broadcast if ads is small
.groupBy("advertiser_id", "campaign_id") # wide: shuffle
.agg(F.count("*").alias("clicks"),
F.countDistinct("user_id").alias("users")))- Narrow steps such as
filter,selectandmapprocess each partition alone. They run in one stage. - Wide steps such as
groupBy,joinanddistinctneed rows from many partitions. Each one starts a new stage.
A broadcast join avoids the shuffle of the big table. The small table is copied to every executor. Spark does this automatically below a size threshold, which is 10 MB by default.
Skew is the other cost. If one key holds 30% of the rows and the data is split into 10 even partitions, the partition with that key gets 30% of the work. That is three times the average share of 10%. Salting the key, or letting adaptive query execution split the skewed partition, spreads it out.
Spark recovers from failures with lineage. It remembers how each partition was computed, and recomputes a lost one from its parents.
Common mistakes
- Treating every join as cheap. Check the plan for shuffles before you trust a job's runtime.
- Ignoring skew. One hot key can make one task run far longer than the rest.
- Assuming lineage protects side effects. Recomputing a partition re-runs any write it makes to an outside system.
Check yourself
- Why does a
filternot start a new stage but agroupBydoes? A filter works on each partition alone. AgroupByneeds rows from many partitions, so Spark must shuffle. - When does Spark use a broadcast join? When the small table is below the size threshold, which is 10 MB by default.
Key takeaways
- Spark runs a graph of operators and keeps intermediate data in memory where it can.
- Narrow steps stay in one stage. Wide steps force a shuffle.
- Shuffles usually dominate cost, through network transfer, spills and serialization.
- Broadcast joins avoid shuffling the large side when the other side is small.
- Skewed keys make one task do most of the work.
Further learning
Next, see how stream processing adds time, windows and lateness, in event time and watermarks.
For the batch picture, see batch and stream processing.
Related
Batch and stream processing
How to move and transform large data sets reliably. Batch jobs run over bounded data, streams run over events as they arrive, and the same ideas of time, state and idempotent writes apply to both.
MapReduce
A batch model with two user functions. Map emits key-value pairs, the framework shuffles them so each key lands on one reducer, and reduce combines the values. Failed tasks are simply rerun.
Sharding and partitioning
Split data across machines by choosing a shard key, hashing or ranging it, routing requests, handling hot spots, resharding without downtime and generating IDs that stay unique.