Distributed Data Processing

Spark and its relatives from the inside: partitions, stages, tasks and the shuffle. Skew, stragglers and salting — why one task in a thousand decides your job's runtime.

Distributed Data Processing

Splitting one computation across many machines, and the three things that buys you — memory, disk bandwidth and cores — against the one thing it costs: a network in the middle of your query.

Q · At what point does a computation stop fitting on one machine, and what does moving it to a cluster actually buy?
The Spark Execution Model

A driver that plans and schedules, executors that hold data and run tasks, and a cluster manager that hands out machines. Almost every confusing Spark failure is explained by knowing which of the three it happened on.

Q · When a Spark job runs, what is running where — and which machine is the one that just ran out of memory?
Partitions: the Unit of Parallelism

A partition is the slice of rows one task processes alone. Too few and the cluster idles; too many and the scheduler dominates. And it is not the same thing as the partition in your storage path.

Q · How many pieces should this data be cut into, and what decides the number — the data, the cluster, or the query?
Stages and Tasks

A stage is everything that can be done without moving data between machines. The boundary between two stages is always a shuffle, and it is always a barrier.

Q · Why does my job have five stages rather than one, and what decided where the cuts are?
The Shuffle
▶ lab

The one operation in a distributed job that uses the network for data. Every row is assigned a destination by key, written to local disk, fetched across the cluster and merged — which is why it dominates the runtime, the cost and the failure modes of almost every job.

Q · Why is the `GROUP BY` the expensive part of my job when the filter above it reads ten times as many rows?
Narrow and Wide Transformations

Narrow: each output partition depends on one input partition, so the work stays where it is. Wide: it depends on many, so the data must move. This single distinction predicts every stage boundary in your job.

Q · Which operations in this transformation are free, and which one just made the engine move the entire dataset across the network?
Data Skew
▶ lab

Real key distributions are not uniform. When one value holds most of the rows, the partitioner faithfully sends them all to one task — and that task becomes the job.

Q · Every task in this stage finished in seconds except one, which has been running for forty minutes. Why, and what does the cluster size have to do with it?
Straggler Tasks

A job finishes when its slowest task does. One task out of a thousand taking twenty times as long makes the whole stage a twenty-times job, and no amount of extra capacity changes it.

Q · If 999 tasks finished in a minute and one is still running, how long is the job — and what would make it shorter?
Salting a Skewed Key

Split the dominant key into several artificial sub-keys so its rows land in several partitions, then combine the partials. It works, it costs an extra stage — and applied to every key instead of the hot one, it does nothing at all.

Q · One key holds most of the rows and I cannot change the grain or broadcast the other side. How do I make that work divisible?
Broadcast Joins

When one side of a join is small enough to send everywhere, the large side never moves and the shuffle disappears. The whole technique rests on a size estimate — and on what happens when that estimate is wrong.

Q · Why did the same join take minutes yesterday and hours today, with the same code and almost the same data?
Lazy Evaluation

Transformations build a plan; nothing runs until an action asks for a result. That is what lets the optimiser see the whole query — and why your error message points at the wrong line and your pipeline ran three times.

Q · Why did the error appear at `write()` when the mistake is twenty lines above it, and why did adding a debug `count()` double the job's runtime?
Query Optimizers

The same question has many correct executions with wildly different costs. An optimiser turns what you asked into how it will run — using rules it can always apply and statistics it can only sometimes trust.

Q · Two queries returning the same answer differ by orders of magnitude in cost. What decided that, and how much of it did I control?
Flink Concepts

A stream-first distributed processor: a dataflow graph deployed once, records flowing through stateful operators, with checkpoints instead of re-runs. Compared with batch and micro-batch on what each one makes easy — not on which is better.

Q · What changes when the job is a long-running dataflow instead of a scheduled batch, and which problems does that make easier or harder?