Distributed computing basics for big data

Hadoop, Spark and Kafka all rest on one simple pattern: split the data, process the pieces at the same time on many machines, and combine the small results, while surviving machines that fail. This lesson builds that pattern step by step in Python you can run, and shows the traps that make distributed answers wrong.

Module 1 · Introduction⏱ 30 minBeginner → AdvancedRuns in your browser (Python)3 real-time scenariosMulti-core program for your PC10 practice problems
1 The story

One lakh answer sheets, one week

Arjun Sir has been made the head examiner for the university's semester exams: 1,00,000 answer sheets, results due in one week. One teacher checks about 50 sheets a day. Riya does the maths and looks worried: one teacher would need 2,000 days.

1,00,000 sheets 1. Split into bundles 1,000 1,000 1,000 … 100 bundles 2. Teachers check in parallel 100 teachers × 1,000 sheets each sends back only a list of marks 3. Combine Head examiner merges 100 lists → results 2,000 teacher-days of work, finished in 20 days with 100 teachers, 5 days with 400. myphatshala.in
Riya

Sir, with 100 teachers it's 1,000 sheets each: 20 days. Still too long!

Arjun Sir

Then 400 teachers: 250 sheets each, five days. But see what else we must organise. Who decides which bundle goes to whom? What if a teacher falls ill on day three? And we don't carry one lakh sheets to one room. Teachers go to the evaluation centres where the sheets already are.

Riya

And at the end, teachers don't send back the sheets, just the marks list. You only merge the lists.

Arjun Sir

Exactly. You've just described distributed computing: split the data, process the parts at the same time, move the workers to the data, send back small results, combine them, and plan for someone dropping out.

Riya

So Hadoop and Spark are… a very organised exam department?

Arjun Sir

A very fast and very strict one. Let's build a small one in Python.

Kabir

Sir, at TiffinGo the orders are split by city. Mumbai alone is bigger than four other cities put together. Does that matter?

Arjun Sir

It matters a lot, Kabir. The job finishes only when the slowest piece finishes. Today you'll see that problem, called data skew, and also what a cluster does when it can't tell whether a machine is slow or dead.

2 Definition

What is distributed computing?

Formal definition (write this in exams)

Distributed computing is a model in which a task is divided into smaller parts that are processed in parallel on multiple independent computers (nodes) connected by a network. The nodes coordinate by passing messages, and the system presents the combined result as if one computer had done the work. Key ideas are partitioning of data, parallel processing, data locality, aggregation of partial results, and fault tolerance through replication and re-execution.

In simple words

Cut a huge job into pieces, give each piece to a different computer, let them all work at the same time, then put the answers together. If one computer breaks, give its piece to another.

Words you'll meet in this lesson

Partition / blockOne piece of the data. HDFS splits files into blocks; Spark calls them partitions.
Master (coordinator)The node that plans the work, assigns tasks and tracks progress.
WorkerA node that does the actual processing of one or more partitions.
TaskOne unit of work: “process partition 7”. A job is made of many tasks.
Data localityRunning a task on the node that already stores its data, so data doesn't travel over the network.
AggregationCombining the small partial results from workers into the final answer.
ReplicationKeeping copies of each partition on different nodes so a failure doesn't lose it.
StragglerA slow task that delays the whole job, often because its partition is much bigger (data skew).

The five-step pattern

1. PartitionSplit the data into blocks and spread them across nodes (with copies)
2. ScheduleThe master assigns one task per block, preferably on the node that holds it
3. Process in parallelEach worker processes only its own block, at the same time as all others
4. CombineSmall partial results are sent over the network and merged
5. RecoverIf a worker fails, its task is re-run on another node that has a copy

Distributed computing at three levels

Pick your level. New to this? Start at Beginner and climb.

Beginner Teamwork with rules

Distributed computing is teamwork with strict rules. Think of a wedding kitchen: one head cook (the master) plans the menu and gives each cook (a worker) one dish. Everyone cooks at the same time, and the head cook puts the plates together at the end.

  • You use it daily: a UPI payment touches your app's servers, your bank, NPCI and the receiver's bank. A Google search is answered by thousands of machines, each searching its own slice of the web.
  • The golden rules: split fairly, work in parallel, send back small answers, and have a plan when someone drops out.

Intermediate How the coordination actually works

  • Heartbeats: every worker tells the master “I'm alive, task 60% done” every few seconds. No heartbeat for a while → the worker is treated as failed and its task is re-run elsewhere.
  • Combiners: each worker first combines its own results (local counts) so that only small summaries travel over the network.
  • Shuffle: when results must be grouped by key across machines (all Mumbai orders together), data is exchanged between workers. This network-heavy step is often the slowest part of a job.
  • Easy vs tricky aggregations: sum, count, min and max combine directly. An average needs (sum, count) pairs; distinct counts need sets (or estimates); a median needs much more care.
  • Speculative execution: if one task runs much slower than the rest, the master starts a backup copy on another node and uses whichever finishes first.

Advanced Partial failure, skew and the fallacies of distributed computing

  • Partial failure: in one computer, things work or crash together. In a cluster, some parts fail while others keep going, and a silent node may be dead, slow or just cut off. A timeout can't tell which.
  • Idempotent tasks: because a task may run twice (a retry plus a “dead” worker that comes back), outputs must be written so that running twice gives the same result, for example by committing only one attempt per task.
  • Data skew: one hot key (one city, one celebrity's account) makes one partition huge. Fixes: split the hot key into sub-keys (salting), choose a better partition key, or handle the hot key separately.
  • No global clock: each machine's clock drifts a little, so “which event happened first” across machines is hard. Systems use sequence numbers or logical clocks instead.
  • The fallacies of distributed computing (from engineers at Sun Microsystems): it is wrong to assume the network is reliable, latency is zero, bandwidth is infinite, the network is secure, the topology doesn't change, there is one administrator, transport cost is zero, and the network is the same everywhere. Every big data tool is designed around these.
  • Module 3 goes deeper into partitioning, replication, consistency and the CAP theorem.

Exam tip: Learn the pattern as partition → parallel process → aggregate, plus the two supporting ideas data locality (“move computation to data”) and fault tolerance (replication + re-execution). This is the foundation of MapReduce, which you'll study in the Hadoop course.

3 Types and ways to use it

Building blocks and shapes of distributed systems

Six building blocks

Partitioning

Split data into blocks, by position (every 128 MB) or by key (all orders of one customer together).

Split

Parallelism

Many tasks run at the same time on different nodes and cores.

Speed

Data locality

Send the small program to the big data, not the big data to the program.

Less network

Aggregation

Workers return small partial results that are merged. Choose results that can be combined correctly.

Combine

Replication

Each block is stored on more than one node (HDFS keeps 3 copies by default).

Safety

Coordination

Someone must know which task runs where, which finished and which failed.

Control

Two kinds of parallelism

Data parallelismTask parallelism
IdeaSame operation on different pieces of dataDifferent operations at the same time
ExampleCount orders in 100 blocks, one block per nodeOne node cleans data while another trains a model and a third builds a report
Used byMapReduce, Spark, most big data processingWorkflow tools like Airflow running independent steps together

Two common architectures

Master–workerPeer-to-peer
HowOne coordinator assigns work; workers report backAll nodes are equal and share responsibilities
ExamplesHDFS (NameNode + DataNodes), Spark (driver + executors), YARNCassandra, BitTorrent
StrengthSimple to reason about and scheduleNo single coordinator to fail
WeaknessMaster must be protected (standby / high availability)Harder to keep all nodes in agreement

Not everything combines by adding. Sums and counts can be added up from partial results. An average of averages is wrong when blocks have different sizes, and counts of distinct customers can't be added either. You'll see both traps in the code below.

4 Step by step

Count chai orders on three machines

  1. Partition the data

    orders = ["chai", "samosa", "chai", "poha", "chai", "samosa"]
    blocks = [orders[0:2], orders[2:4], orders[4:6]]
    print(blocks)
    [['chai', 'samosa'], ['chai', 'poha'], ['chai', 'samosa']]
    In a real cluster, a 30 GB file becomes 240 blocks of 128 MB, and each block is stored on three different nodes.
  2. Each machine counts only its block

    block = ["chai", "poha"]           # machine 2's block
    counts = {}
    for item in block:
        counts[item] = counts.get(item, 0) + 1
    print(counts)
    {'chai': 1, 'poha': 1}
    All three machines run this at the same time, each on the block stored on its own disk. Nothing is sent over the network yet: that's data locality.
  3. Send back small results

    Machine 1 sends {'chai': 1, 'samosa': 1}, machine 2 sends {'chai': 1, 'poha': 1}, machine 3 sends {'chai': 1, 'samosa': 1}.

    Each block may be 128 MB, but its partial result is a few bytes: one number per item. The network carries the small summaries, not the data.
  4. Combine

    partials = [{"chai": 1, "samosa": 1}, {"chai": 1, "poha": 1}, {"chai": 1, "samosa": 1}]
    total = {}
    for p in partials:
        for item, n in p.items():
            total[item] = total.get(item, 0) + n
    print(total)
    {'chai': 3, 'samosa': 2, 'poha': 1}
    The same answer as counting all six orders on one machine. Counts combine by simple addition, which is why counting is the classic first distributed program.
  5. A machine fails

    Machine 2 crashes halfway through its block.

    The master notices that machine 2 stopped reporting (it misses its regular heartbeat). Another node holds a copy of block 2, so the master re-runs just that one task there. Blocks 1 and 3 are not redone.
5 See it happen

A distributed job: what Riya sees, and what the cluster does

Step through the six frames. Left: the job's progress page. Right: the master and four workers.

Split, process, survive, combine 6 steps
What you see Job: count_orders Input: orders.csv (512 MB) Status: planning… Submitted ✓ Tasks: task 1task 2task 3task 4 4 running at the same time failed task 3: worker lost retry 3 of 4 done · task 3 retrying 4 of 4 done · combining… Status: SUCCEEDED in 41 s chai 9,41,220 samosa 6,02,115 vada pav 5,87,930 poha 3,10,402 The retry didn't change the answer. myphatshala.in
Behind the screen Master Worker 1 Worker 2 Worker 3 Worker 4 block 1 block 2 block 3 block 4 copy of 3 copy of 1 Each task goes to the worker that already stores its block: data locality. All four count their own block at the same time. ✗ No heartbeat from worker 3. Master marks task 3 as failed. running task 3 Worker 1 has a copy of block 3, so only task 3 is re-run there. Small partial counts flow up to the master. Blocks are 128 MB; each result is a few bytes. total = p1 + p2 + p3 + p4 Merged result is written out. Job done. myphatshala.in

What can go wrong in a distributed system

ProblemWhat it meansUsual fix
Node failureA machine crashes mid-taskHeartbeats detect it; re-run the task on a replica
Network delayMessages are slow or lostTimeouts, retries, keep data local
Stragglers / skewOne task is much slower than the restSplit data more evenly; run a backup copy of slow tasks
Wrong combinePartial results merged incorrectlySend sum and count, not averages; use sets for distinct values
Duplicate workA retried task writes its output twiceMake tasks idempotent: running twice gives the same result
6 Real-world use

Real-time scenarios: a cluster at work

Three live scenarios: whether to move the data or the program, a job held up by one giant partition, and an advanced one about a worker that goes silent and then comes back.

Real-time scenario 1

Move the data, or move the program?

A worker needs to process a 100 GB block stored on another machine. It could copy the data over the network, or the program could be sent to the machine that has the data. Watch the difference.

Data locality 5 steps
Animated example Node A has the program Node B 100 GB 1 Gbps network ≈ 125 MB/s Option 1: copy the data to the program. Option 2: send the program to the data. data Copying 100 GB: 1,02,400 MB ÷ 125 MB/s ≈ 819 s ≈ 14 minutes, network fully busy 5 KB Sending a 5 KB program takes milliseconds. Node B reads 100 GB from its own disk, then returns a result of a few KB. “Move computation to data.” myphatshala.in
Real-time scenario 2

Data skew: one giant partition holds up the whole job

TiffinGo's daily report splits orders by city, one city per worker. Mumbai has six times more orders than any other city. Watch the progress bars, then see two standard fixes.

Task progress per worker 5 steps
Animated example Job starts: orders split by cityW1Pune · 2 GB0%W2Delhi · 2 GB0%W3Chennai · 2 GB0%W4Kolkata · 2 GB0%W5Mumbai · 12 GB0%Five workers, one city each. Looks fair: five machines,five partitions. But Mumbai is six times bigger.After 2 minutesW1Pune · 2 GB✓ doneW2Delhi · 2 GB✓ doneW3Chennai · 2 GB✓ doneW4Kolkata · 2 GB✓ doneW5Mumbai · 12 GB17%Four workers have finished.Mumbai has done only one sixth of its work.After 12 minutesW1Pune · 2 GBidle 10 minW2Delhi · 2 GBidle 10 minW3Chennai · 2 GBidle 10 minW4Kolkata · 2 GBidle 10 minW5Mumbai · 12 GB✓ doneThe job takes as long as its slowest task: 12 minutes.Four machines sat idle for 10 minutes. This is data skew.Fix 1: split the hot key (salting)W1Pune + Mumbai-1 · 4 GB✓ 4 minW2Delhi + Mumbai-2 · 4 GB✓ 4 minW3Chennai + Mumbai-3 · 4 GB✓ 4 minW4Kolkata + Mumbai-4 · 4 GB✓ 4 minW5Mumbai-5,6 · 4 GB✓ 4 minMumbai is split into 6 sub-keys, spread over all workers.Every worker has 4 GB, and the job finishes in about 4 minutes.Fix 2: a slow machine? Run a backup copyW1Pune · 2 GB✓ doneW2Delhi · 2 GB✓ doneW3Chennai · 2 GBslow disk 40%W4Kolkata · 2 GB✓ doneW1backup of W3 task✓ winsWhen the data is fair but a machine is slow, the master startsa backup copy elsewhere and keeps whichever finishes first. myphatshala.in
Real-time scenario 3 · advanced

Slow or dead? The worker that came back

A cluster has no way to look inside a silent machine. Watch how heartbeats and timeouts handle a worker that goes quiet, and the surprising bug that appears when it comes back.

Heartbeats, timeouts and retries 5 steps
Animated example MasterW1W2W3W4 (free)♥ “alive, task 60% done” every 3 sHeartbeats: every worker reports in every 3 seconds.W3 is running task 7 on its block of Chennai orders.W1W2W3W4 (free)? silent for 12 sW3 goes silent. Crashed? Slow? Network cable loose?From the master’s side, all three look exactly the same.W1W2W3 ✗W4: task 7re-run task 7Timeout (30 s): W3 is marked dead. Task 7 re-runs on W4,using a replica of the same block stored on W4.W1W2W3: task 7W4: task 72 results for 1 task!W3 was only cut off. It reconnects and finishes task 7 too.Add both and the Chennai orders are counted twice.W1W2W3: ignoredW4: keptfirst attempt winsFix: each attempt writes to a temporary place; the mastercommits only one attempt per task. Retries become safe (idempotent). myphatshala.in

Where distributed computing runs every day

1. Spark and Hadoop jobs

A Spark job is exactly this lesson: the driver (master) splits the data into partitions, executors (workers) process them in parallel, and failed tasks are retried. Hadoop MapReduce does the same with map and reduce tasks.

Big file→Partitions → parallel tasks → combine→Result
A–MN–Z

2. Distributed databases

Databases like Cassandra and MongoDB split tables across nodes by key (called sharding): customers A–M on some nodes, N–Z on others, each with replicas. A query for one customer goes straight to the right node.

Query by customer id→Route to the shard that owns it→Fast reply

3. Event streams with Kafka

Kafka splits each stream of events into partitions stored on different brokers, with replicas. Many consumers read different partitions in parallel, so millions of events per second can be handled.

Events→Partitions on many brokers→Parallel consumers

4. Content delivery networks (CDNs)

Videos and images are copied to servers in many cities, and your phone fetches from the nearest one. That's replication and locality applied to users instead of processing.

Video→Copies in many cities→Nearest server answers

5. Large-scale testing and builds

Big software companies run thousands of automated tests on every code change. They are split across many machines and run in parallel, so results come back in minutes instead of hours.

10,000 tests→Split across 200 machines→Report in minutes

Examples are simplified to show the pattern. Real systems add many more details.

7 Run the code

A tiny cluster in Python

Twelve canteen orders, three “machines”. The program partitions the data, lets each machine count only its own block, then combines the partial counts. On a real cluster the three counts would run at the same time on different computers. Then try the challenges: real parallel speed-up, a failure, Amdahl's law, a straggler and the average-of-averages trap.

orders = ["chai", "samosa", "chai", "vada pav", "chai", "poha",
          "samosa", "chai", "coffee", "chai", "samosa", "poha"]
machines = 3

# 1. PARTITION: split the data into one block per machine
size = len(orders) // machines
blocks = [orders[i * size:(i + 1) * size] for i in range(machines)]

# 2. PROCESS: each machine counts only its own block
def count_block(block):
    counts = {}
    for item in block:
        counts[item] = counts.get(item, 0) + 1
    return counts

partials = [count_block(b) for b in blocks]
for i, p in enumerate(partials, 1):
    print("Machine", i, "->", p)

# 3. COMBINE: merge the small partial results
total = {}
for p in partials:
    for item, n in p.items():
        total[item] = total.get(item, 0) + n
print("Final     ->", total)
Machine 1 -> {'chai': 2, 'samosa': 1, 'vada pav': 1} Machine 2 -> {'chai': 2, 'poha': 1, 'samosa': 1} Machine 3 -> {'coffee': 1, 'chai': 1, 'samosa': 1, 'poha': 1} Final -> {'chai': 5, 'samosa': 3, 'vada pav': 1, 'poha': 2, 'coffee': 1}
  • orders[i * size:(i + 1) * size]Slicing gives machine 1 items 0–3, machine 2 items 4–7, machine 3 items 8–11: one partition each.
  • def count_block(block):The same small function is sent to every machine. Shipping code to the data is data locality.
  • partials = [count_block(b) for b in blocks]Here the calls run one after another. On a cluster each call runs on a different node at the same time.
  • total[item] = total.get(item, 0) + nCounts combine by adding. That is why counting is the classic first distributed program.

Run it on your PC: use all your CPU cores

A plain Python loop uses one core. This program counts prime numbers below 20 lakh, first on one core, then split into blocks and run on all your cores with multiprocessing. It is a real parallel program on one machine, using the same split–process–combine pattern a cluster uses across machines. Save it as use_all_cores.py.

Split the work across cores

import os, time
from multiprocessing import Pool


def count_primes(block):
    """Count the prime numbers in one block (a range of numbers)."""
    lo, hi = block
    count = 0
    for n in range(max(lo, 2), hi):
        if all(n % d for d in range(2, int(n ** 0.5) + 1)):
            count += 1
    return count


if __name__ == "__main__":           # needed on Windows for multiprocessing
    cores = os.cpu_count()
    N = 2_000_000
    step = N // cores
    blocks = [(i * step, (i + 1) * step) for i in range(cores)]

    start = time.time()
    serial = sum(count_primes(b) for b in blocks)
    t1 = time.time() - start
    print(f"Serial   (1 core) : {serial} primes in {t1:.1f} s")

    start = time.time()
    with Pool(cores) as pool:
        parallel = sum(pool.map(count_primes, blocks))
    t2 = time.time() - start
    print(f"Parallel ({cores} cores): {parallel} primes in {t2:.1f} s")
    print(f"Speed-up: {t1 / t2:.1f}x")

    # Big numbers take longer to test, so the last block is the slowest.
    # Many small blocks spread the work more evenly between the cores.
    small = N // (cores * 8)
    many = [(i * small, (i + 1) * small) for i in range(cores * 8)]
    start = time.time()
    with Pool(cores) as pool:
        balanced = sum(pool.map(count_primes, many))
    t3 = time.time() - start
    print(f"Parallel, {len(many)} small blocks: {balanced} primes in {t3:.1f} s, speed-up {t1 / t3:.1f}x")

# In a terminal:  python use_all_cores.py
Serial (1 core) : 148933 primes in 7.0 s Parallel (2 cores): 148933 primes in 4.9 s Speed-up: 1.4x Parallel, 16 small blocks: 148933 primes in 4.4 s, speed-up 1.6x

Recorded on a small 2-core cloud machine. On a 4- or 8-core laptop the speed-up will be larger, and your times will differ. Notice two real-world lessons: the answer is identical every time, and the speed-up is less than the number of cores, partly because bigger numbers take longer to test, so the last block is a straggler. Many smaller blocks balance the work better.

8 Line by line

Partition, count, combine, one line at a time

The mini cluster with six orders and two machines. Watch count_block() get its own frame for each block and return a small dictionary, then watch the partial results merge into total.

Worked examples: real problems, solved and traced in memory

Four problems, from beginner to advanced: splitting fairly, combining correctly, recovering from failures and fixing a skewed partition. Each runs live and is traced in memory.

Example 1BeginnerPlatform · partitioning

Split records into near-equal blocks

Problem statement

Split 10 records across 3 machines so that block sizes differ by at most one. (Plain slicing with 10 // 3 would leave one record out.)

Input
records R1..R10, 3 machines
Expected output
Machine 1 : ['R1', 'R2', 'R3', 'R4']
Machine 2 : ['R5', 'R6', 'R7']
Machine 3 : ['R8', 'R9', 'R10']

Approach

  1. Use divmod(10, 3) to get the base size (3) and the remainder (1).
  2. The first “remainder” blocks get one extra record.
  3. Track the start position as you cut each block.

Solution: run it live

What happens in memory, step by step

Recorded from a real Python run: press Next to execute one line at a time. Watch variables change in each frame, and lists and dictionaries (numbered #1, #2 …) fill up as objects.

Example 2IntermediateRetail · aggregation

The correct distributed average

Problem statement

Two stores compute their bills locally. Store A has 8 bills of ₹100, store B has 2 bills of ₹1,000. Combine their results to get the true average bill.

Input
A: 8 × 100 · B: 2 × 1000
Expected output
Partials: [(800, 8), (2000, 2)]
True average: 280.0

Approach

  1. Each store sends back (sum, count), not its average.
  2. Add all the sums and all the counts.
  3. Divide once at the end.

Solution: run it live

What happens in memory, step by step

Recorded from a real Python run: press Next to execute one line at a time. Watch variables change in each frame, and lists and dictionaries (numbered #1, #2 …) fill up as objects.

Example 3IntermediateCluster manager · fault tolerance

Reassign failed tasks

Problem statement

Four tasks were sent to workers. Task T3 failed. The master must find failed tasks and give them to a healthy worker, without re-running tasks that succeeded.

Input
T1 done, T2 done, T3 failed, T4 done · healthy workers W1, W2
Expected output
Retrying T3 on W1
All done: True

Approach

  1. Keep the status of every task in a dictionary.
  2. Loop over the tasks; skip finished ones.
  3. Give each failed task to the next healthy worker and mark it done after the retry.

Solution: run it live

What happens in memory, step by step

Recorded from a real Python run: press Next to execute one line at a time. Watch variables change in each frame, and lists and dictionaries (numbered #1, #2 …) fill up as objects.

Example 4AdvancedData platform · skew

Detect a hot key and salt it

Problem statement

Orders are partitioned by city. Mumbai's partition is far bigger than the rest, so one task runs six times longer. Measure the skew (largest ÷ average), then split the hot key into 6 sub-keys and show the new largest partition.

Input
Pune 2, Delhi 2, Chennai 2, Kolkata 2, Mumbai 12 (GB)
Expected output
Hot key: Mumbai | skew ratio: 3.0
Partitions now: 10 | largest: 2 GB

Approach

  1. Average size = total ÷ number of partitions. Skew ratio = largest ÷ average.
  2. Build a new dictionary. For the hot city, add sub-keys Mumbai-0 … Mumbai-5, each with one sixth of the data.
  3. Copy every other city unchanged, then compare the largest partition before and after.

Solution: run it live

What happens in memory, step by step

Recorded from a real Python run: press Next to execute one line at a time. Watch variables change in each frame, and lists and dictionaries (numbered #1, #2 …) fill up as objects.

9 Quiz and revision

Check yourself

Quick revision

Lesson 1.3 in one screen

  • Heartbeats + timeouts detect failed workers; failed tasks are re-run on a node with a replica.
  • Data skew: one hot key makes one huge partition (a straggler). Fix with salting or a better key; slow machines get speculative backup tasks.
  • Retries mean a task can run twice, so outputs must be idempotent (commit one attempt per task).
  • Distributed computing: many networked nodes work on parts of one job in parallel and combine the results.
  • Pattern: partition → process in parallel → aggregate.
  • Data locality: send the small program to the big data, not the reverse.
  • Master–worker (HDFS, Spark, YARN) vs peer-to-peer (Cassandra).
  • Fault tolerance: heartbeats detect failures; replicas let failed tasks re-run elsewhere.
  • Combine carefully: sums and counts add up; average of averages is wrong; distinct counts need sets.
  • Stragglers: the job waits for the slowest task. Amdahl's law: speed-up ≤ 1 ÷ serial fraction.

Interview and viva questions

What is distributed computing? How is it different from parallel computing on one machine?

Parallel computing runs parts of a task at the same time, often on cores sharing one machine's memory. Distributed computing spreads the task across separate computers connected by a network, each with its own memory and disk, coordinating by messages. It scales further and survives machine failures, but must deal with network delays and partial failures.

Explain data locality and why it matters in Hadoop.

Data locality means scheduling a task on the node that already stores its data block. Network bandwidth across a cluster is much scarcer than local disk bandwidth, so moving a few kilobytes of code instead of gigabytes of data saves time and avoids congestion. Hadoop's scheduler prefers node-local, then rack-local, then remote placement.

How does a distributed system handle the failure of a node?

Workers send heartbeats to a coordinator. When heartbeats stop, the node is marked dead. Its data is still available because blocks are replicated on other nodes, and its unfinished tasks are re-run on nodes holding those replicas. Tasks are designed to be idempotent so re-running them doesn't corrupt results.

What is Amdahl's law?

It gives the maximum speed-up from parallelising a job: speed-up = 1 ÷ ((1 − p) + p ÷ n), where p is the parallel fraction and n the number of processors. The serial part sets a hard limit: if 5% is serial, the job can never run more than 20× faster.

What are the main challenges of distributed systems?

Partial failures (some nodes fail while others work), network latency and lost messages, keeping replicas consistent, uneven work (skew and stragglers), coordinating many nodes, and combining partial results correctly. Frameworks like Hadoop and Spark handle much of this for the programmer.

What is data skew and how do you fix it?

Data skew happens when one partition key has far more data than others, so one task runs much longer and the whole job waits for it. Fixes include salting the hot key (splitting it into several sub-keys and combining their results later), choosing a partition key with more even values, handling the hot keys separately (for example, broadcasting a small table in a join), and in Spark enabling adaptive query execution, which can split skewed partitions automatically.

Practice problems

Split–process–combine exercises. The last three are business tasks about time, cost and correctness.

P1Easy

Chunks of three

Split the list 1 to 8 into chunks of at most 3 items.

Input
[1..8]
Expected output
[[1, 2, 3], [4, 5, 6], [7, 8]]
Show solution and explanation
nums = list(range(1, 9))
chunks = [nums[i:i + 3] for i in range(0, len(nums), 3)]
print(chunks)
[[1, 2, 3], [4, 5, 6], [7, 8]]

How it works: range(0, 8, 3) gives start positions 0, 3, 6; the last chunk is shorter.

P2Easy

Merge two partial counts

Machine 1 counted {"chai": 4, "poha": 1} and machine 2 counted {"chai": 2, "samosa": 3}. Print the combined counts.

Input
two dictionaries
Expected output
{'chai': 6, 'poha': 1, 'samosa': 3}
Show solution and explanation
p1 = {"chai": 4, "poha": 1}
p2 = {"chai": 2, "samosa": 3}
total = dict(p1)
for item, n in p2.items():
    total[item] = total.get(item, 0) + n
print(total)
{'chai': 6, 'poha': 1, 'samosa': 3}

How it works: Copy the first result, then add the second item by item.

P3Easy

Total from partial sums

Four workers returned partial sums 1200, 950, 1430 and 880. Print the total.

Input
[1200, 950, 1430, 880]
Expected output
Total: 4460
Show solution and explanation
print("Total:", sum([1200, 950, 1430, 880]))
Total: 4460

How it works: Sums combine by adding: the simplest kind of aggregation.

P4Medium

Global maximum from local maximums

Each machine finds the largest bill in its block. Combine them to get the largest bill overall.

Input
blocks [120, 450, 80], [990, 30], [300, 710]
Expected output
Local: [450, 990, 710]
Global max: 990
Show solution and explanation
blocks = [[120, 450, 80], [990, 30], [300, 710]]
local_max = [max(b) for b in blocks]
print("Local:", local_max)
print("Global max:", max(local_max))
Local: [450, 990, 710] Global max: 990

How it works: Max of maxes is correct (unlike average of averages), so each node only needs to send one number.

P5Medium

Amdahl's law

95% of a job can run in parallel. Print the speed-up on 20 machines and the limit.

Input
p = 0.95, n = 20
Expected output
Speed-up: 10.26
Limit: 20 x
Show solution and explanation
p, n = 0.95, 20
print("Speed-up:", round(1 / ((1 - p) + p / n), 2))
print("Limit:", round(1 / (1 - p)), "x")
Speed-up: 10.26 Limit: 20 x

How it works: Even 5% serial work caps the speed-up at 20×; on 20 machines you get about 10×.

P6Advanced

Which workers are dead?

The master marks a worker as dead if its last heartbeat is more than 30 seconds old. Given the last heartbeat time of each worker and the current time, print the dead workers and the tasks to re-run.

Input
now = 1000 s
Expected output
Dead workers: ['W3', 'W5']
Tasks to re-run: [4, 5, 7]
Show solution and explanation
now = 1000
last_beat = {"W1": 998, "W2": 990, "W3": 955, "W4": 999, "W5": 960}
tasks = {"W1": [1, 2], "W2": [3], "W3": [4, 5], "W4": [6], "W5": [7]}
TIMEOUT = 30
dead = [w for w, t in last_beat.items() if now - t > TIMEOUT]
rerun = [task for w in dead for task in tasks[w]]
print("Dead workers:", dead)
print("Tasks to re-run:", rerun)
Dead workers: ['W3', 'W5'] Tasks to re-run: [4, 5, 7]

How it works: W3 has been silent 45 s and W5 40 s, both over the 30 s timeout. Their tasks are re-scheduled on healthy workers that hold replicas of the same blocks.

P7Advanced

Commit one attempt per task

Because of retries, the same task can report results more than once. Keep only the first result for each task id, and print the correct total.

Input
results (task, attempt, orders)
Expected output
Naive total  : 670
Correct total: 435
Show solution and explanation
results = [(1, "a", 120), (2, "a", 95), (3, "a", 140),
           (3, "b", 140), (4, "a", 80), (2, "b", 95)]
committed = {}
for task, attempt, orders in results:
    if task not in committed:
        committed[task] = (attempt, orders)
naive = sum(r[2] for r in results)
correct = sum(o for _, o in committed.values())
print("Naive total  :", naive)
print("Correct total:", correct)
Naive total : 670 Correct total: 435

How it works: Adding every report counts tasks 2 and 3 twice. Committing one attempt per task makes retries harmless: this is the idempotent output idea from scenario 3.

P8Business problem

Copy the data or move the code?

A job needs 500 GB that sits on another node. The network gives 10 Gbps (about 1,250 MB/s). Print the copy time in minutes. Sending the 10 KB program takes well under a second.

Input
500 GB, 1250 MB/s
Expected output
Copying data: 6.8 minutes
Show solution and explanation
mb = 500 * 1024
print("Copying data:", round(mb / 1250 / 60, 1), "minutes")
Copying data: 6.8 minutes

How it works: About 7 minutes of a fully busy link for one block. Data locality avoids this entirely.

P9Business problem

When does the job finish?

Six tasks run on six workers at the same time. Their times are 4, 5, 4, 21, 5 and 4 minutes. Print the job time and the average task time.

Input
[4, 5, 4, 21, 5, 4]
Expected output
Job time: 21 minutes
Average task: 7.2 minutes
Show solution and explanation
times = [4, 5, 4, 21, 5, 4]
print("Job time:", max(times), "minutes")
print("Average task:", round(sum(times) / len(times), 1), "minutes")
Job time: 21 minutes Average task: 7.2 minutes

How it works: The straggler (21 min) decides the job time, not the average (7.2 min). Fix the skew or run a backup copy of the slow task.

P10Business problem

Distinct customers across stores

Three stores report the customer ids they served. Print the number of distinct customers overall. (Adding the three counts would be wrong.)

Input
store ids with overlaps
Expected output
Sum of counts (wrong): 8
Distinct customers   : 5
Show solution and explanation
stores = [{"C1", "C2", "C3"}, {"C2", "C4"}, {"C1", "C4", "C5"}]
print("Sum of counts (wrong):", sum(len(s) for s in stores))
print("Distinct customers   :", len(set().union(*stores)))
Sum of counts (wrong): 8 Distinct customers : 5

How it works: Customers who visit several stores would be counted more than once. Combine the sets, then count.

Real-world scenario questions (asked in company interviews)

Distributed-computing problems that show up in real jobs and interviews. Decide your answer first, then open the model answer.

Retail analytics · correctnessFresher

The national average bill is wrong

Each region computes its average bill value and sends it to head office, which averages the 10 regional averages for the national figure. Finance says the number doesn't match their records.

The interviewer is checking: do you know which results can be combined, and how to combine averages correctly?

Show a strong answer

An average of averages gives every region equal weight, even though regions have very different numbers of bills.

  • Each region should send (total value, number of bills).
  • Head office adds the totals and the counts, then divides once.
  • Medians and distinct counts need similar care: they can't be combined by simple addition either.

Avoid: “weighting by region size” using population or guesses instead of the actual counts.

E-commerce · Spark job1–3 years

199 tasks finish in 2 minutes, one takes 40

A daily job groups orders by seller. The Spark UI shows 199 tasks finishing in about 2 minutes and one task running for 40 minutes. Adding more machines didn't help.

The interviewer is checking: can you recognise data skew and stragglers, and explain why more machines don't fix them?

Show a strong answer

One partition holds far more data than the others, probably a few huge sellers. The job waits for that straggler; extra machines only speed up tasks that were already fast.

  • Check record counts per key to confirm the skew.
  • Split hot keys (add a random “salt” to spread one seller across several partitions, then combine).
  • Pre-aggregate before the big grouping so less data moves.
  • Enable the engine's skew-handling features where available.

Avoid saying: “Just add more nodes.”

Any company · conceptsFresher

“Why not copy all the data to one powerful machine first?”

A teammate suggests copying 50 TB from the cluster to one large server each night to run the report there, “because it's simpler”.

The interviewer is checking: do you understand data locality and network limits, with numbers?

Show a strong answer

At 10 Gbps (about 1.25 GB/s), copying 50 TB takes roughly 11–12 hours of a fully busy link, before any processing, and the single server then hits the walls from Lesson 1.2.

  • Process the data where it lives: run the report as a distributed job on the cluster.
  • Move only the small results (aggregates) to the reporting server or dashboard.
  • Consider processing only the new day's data incrementally.

Avoid: ignoring network transfer time when comparing designs.

Fintech · reliability1–3 years

A worker died at 90% of the job

A 3-hour nightly job runs on 50 workers. At 2 h 40 min, one worker's machine reboots. A junior engineer wants to restart the whole job from the beginning. What should happen instead, and what must the job's code guarantee?

The interviewer is checking: do you know task-level retry and idempotency?

Show a strong answer

Frameworks like Spark and MapReduce re-run only the failed tasks on other nodes using replicated data; finished tasks are not redone. The job finishes a few minutes late, not three hours late.

  • Task output must be idempotent: if a task runs twice, its result is written once (for example, write to a temporary location and commit atomically).
  • Avoid side effects inside tasks (sending emails or payments) that would repeat on retry.
  • For very long pipelines, add checkpoints between stages.

Avoid: designs where a retry double-counts money or sends duplicate notifications.