The Two Paradigms
bounded and slow, or unbounded and fastBatch processes a bounded, finite dataset โ yesterday's logs, the whole user table โ in one big job. High throughput, high latency: answers arrive in minutes to hours. Stream processes an unbounded, never-ending flow of events, producing results within seconds of each event arriving.
The split is really input shape. Batch has an end; stream never does. Most real systems run both: a stream layer for fresh, approximate answers and a batch layer for complete, correct ones.
BATCH STREAM
[ bounded dataset ] โฆeventโฆeventโฆeventโฆโถ (never ends)
โ run over all of it โ process each as it arrives
โผ โผ
result in minutesโhours result in seconds
high throughput, high latency low latency, incremental
"daily report", "reindex everything" "trending now", "live dashboard"
Batch Fundamentals
MapReduce and the shuffleMapReduce is the mental model even when the engine is modern. Map transforms each input record into key-value pairs in parallel. Shuffle groups all pairs with the same key onto the same node. Reduce aggregates each group. Word count: map emits (word, 1), shuffle gathers each word, reduce sums.
input split โโถ MAP โโถ (k,v) pairs โโ
input split โโถ MAP โโถ (k,v) pairs โโผโ SHUFFLE โโถ REDUCE โโถ output
input split โโถ MAP โโถ (k,v) pairs โโ (group by key) (aggregate)
โฒ โฒ
parallel, cheap the EXPENSIVE part:
moves data across the network
The shuffle is where the cost lives โ it moves data across the network to co-locate keys, and it's the bottleneck of every batch job. Modern engines like Spark keep the same map/shuffle/reduce model but run in memory and chain stages, cutting the disk round trips MapReduce paid between steps. ETL vs ELT is a related choice: transform before loading into the warehouse (ETL) or load raw and transform inside it (ELT, now the default given cheap warehouse compute).
Stream Fundamentals
events flowing through a topologyStream processing (Flink, Kafka Streams) runs events through a topology of operators โ a graph of transforms, filters, and aggregations that data flows through. Operators come in two kinds, and the difference drives everything hard about streaming.
Each event handled independently โ map, filter, transform. No memory between events, so they scale trivially and recover for free. Any node can process any event.
Aggregations, joins, counts โ they remember across events. That state must be partitioned by key, kept in memory, and checkpointed so it survives a crash. All the difficulty of streaming is managing this state.
Windowing
slicing an infinite stream into finite chunksYou can't sum an infinite stream โ you sum a window of it. Three shapes cover most needs, and the deep problem is which clock defines them.
| Window | Shape | Use |
|---|---|---|
| Tumbling | Fixed, non-overlapping (every 1 min) | Per-minute counts, clean buckets |
| Sliding | Fixed size, overlapping (5 min, every 1 min) | Moving averages, rolling metrics |
| Session | Bounded by a gap of inactivity | User sessions, bursts of activity |
The subtlety is event time vs processing time. Event time is when the event actually happened; processing time is when your system saw it. They differ because events arrive late and out of order โ a phone was offline, a network stalled. Bucket by processing time and a delayed event lands in the wrong window, corrupting the count.
Exactly-Once Processing
what the claim actually meansStreaming engines advertise "exactly-once," and it needs unpacking. Delivery over a network is at-least-once; what's achievable is exactly-once effect, built from three pieces: checkpointing (periodically snapshot operator state and input offsets together), replayable sources (rewind the log to the last checkpoint after a crash), and idempotent or transactional sinks (writing the same result twice has no extra effect).
Lambda and Kappa Architectures
two layers, or one with replayLambda runs two layers in parallel: a batch layer that recomputes complete, correct results slowly, and a speed layer that gives fast approximate results now. Queries merge the two. The cost is maintaining the same logic twice, in two codebases that drift.
Kappa drops the batch layer. Keep everything as a replayable log and use the stream engine for both: for a "recompute from scratch," just replay the log from the beginning. One codebase, one system. Given durable logs and mature stream engines, kappa is winning.
LAMBDA KAPPA
events โโฌโโถ batch layer (slow, exact) events โโถ log โโถ stream engine
โโโถ speed layer (fast, approx) โ
โ โโ live results
โผ โโ reprocess by
merge at query replaying the log
two codebases, they drift one codebase, replay for correctness
Top-K and Counting at Scale
exact counting is unaffordable โ say so"Trending topics" and "unique visitors" sound like GROUP BY. At billions of events, exact answers need too much memory โ a counter per distinct item, a set of every visitor ID. The move is probabilistic sketches: fixed-size structures that trade a small, bounded error for enormous memory savings.
| Need | Sketch | Trades |
|---|---|---|
| Frequency of each item | Count-Min Sketch | May overcount slightly, never undercounts |
| Count of distinct items | HyperLogLog | ~2% error on cardinality, tiny memory |
| Top-K heavy hitters | Count-Min + a heap | Approximate ranking of the busiest keys |
These merge cleanly, which is what makes them work in a distributed pipeline: each partition builds its own sketch, and you combine them into a global answer without re-scanning the data. Count per window (tumbling or sliding), keep heavy hitters per window, merge across partitions.
Quick Reference
paradigms, windows, and question-shapes| Batch | Stream | |
|---|---|---|
| Input | Bounded, finite | Unbounded, continuous |
| Latency | Minutes to hours | Seconds |
| Throughput | Very high | Incremental |
| Tools | Spark, MapReduce | Flink, Kafka Streams |
| Question shape | Technique |
|---|---|
| "Trending / top-K now" | Count-Min + heap, over windows |
| "Unique visitors / distinct count" | HyperLogLog |
| "Moving average / rolling metric" | Sliding window |
| "Daily report / full recompute" | Batch layer |
| "Late, out-of-order events" | Event time + watermarks |