Practice this topic in a realistic system design interview
Not every data question needs an instant answer. A daily revenue report can run overnight. Fraud detection, delivery tracking, and live alerts cannot wait that long. They need fresh data while events are still happening.
Batch processing works on a fixed set of data with a clear start and end. Stream processing handles events continuously as they arrive, so it never really stops.
Most real systems use both. The right choice depends on four simple questions: How fresh does the answer need to be? How exact does it need to be? How much will it cost? How much complexity can the team operate safely?
This chapter explains the difference between batch and stream processing, why streaming is harder to run, where micro-batch fits, and how to choose the right approach.
Batch processing reads a fixed amount of data, does some work on it, and writes the result. The job has a clear beginning and end.
For example, an ecommerce company might process yesterday's orders at 02:00. The job calculates revenue by category, updates warehouse tables, and prepares finance reports before the business day starts.
These traits explain why batch jobs are usually easier to reason about, and why the results arrive later.
| Characteristic | Practical Meaning |
|---|---|
| Latency | Usually minutes to hours. Results are available after the job finishes. |
| Throughput | High. The setup cost is spread across many records. |
| Dataset shape | Bounded. The input is a known slice of data, such as one partition, one table snapshot, or one date range. |
| Fault tolerance | Straightforward compared with streaming. Failed jobs can often retry from checkpoints or rerun from input data. |
| Correctness model | Easier to validate because inputs and outputs can be compared after the job completes. |
| Operational profile | Often bursty. Clusters may scale up for scheduled jobs and scale down afterward. |
Batch processing is common for daily analytics, ETL and ELT pipelines, machine learning training, embedding generation, billing, settlement, data backfills, and compliance exports. These jobs work well in batch because they can wait for complete input, run the same way again, and validate results before publishing them.
A batch job usually follows three steps:
Batch systems can do things that are difficult in streaming systems. They can sort the whole input, split large datasets into better partitions, scan the data multiple times, run expensive joins, and check the output before publishing it.
That is why batch remains common even in systems that also need real-time behavior. When you need an exact answer over a large amount of historical data, batch is usually the first tool to consider.
Apache Spark is common for large ETL jobs, feature pipelines, backfills, and joins. Hadoop MapReduce still appears in older Hadoop systems and very large sequential jobs. Hive, Trino, Presto, dbt, and cloud data warehouses are often used for SQL transformations, interactive queries, scheduled ELT, BI tables, and controlled reporting.
Hadoop MapReduce is still important historically, but most new systems start with Spark, SQL engines, managed warehouses, or lakehouse-style platforms rather than writing raw MapReduce jobs.
Stream processing reads events continuously and updates results as data arrives. The input does not have a natural end. The processor keeps running, remembers state when needed, and writes output to downstream systems.
A payment platform, for example, cannot wait for an overnight batch job to detect stolen cards. It needs to score each transaction during authorization, or immediately beside that path.
Compared with batch, streaming trades simplicity for freshness.
| Characteristic | Practical Meaning |
|---|---|
| Latency | Usually milliseconds to seconds, depending on the engine, stored state, destination, and reliability requirements. |
| Throughput | Can be very high, but each event has less time to share setup cost. |
| Dataset shape | Unbounded. The system sees a continuous event stream, not a complete table. |
| State | Often required for counts, joins, deduplication, sessions, and pattern detection. |
| Fault tolerance | Harder than batch. The system must recover state and resume from the right offsets. |
| Correctness model | Depends on event time, watermarks, deduplication, safe retries, and how the destination handles writes. |
Stream processing is common for fraud detection, monitoring, alerting, live operational dashboards, recommendations, IoT telemetry, content moderation, and Change Data Capture (CDC). These workloads lose value when the system waits for the next scheduled batch job.
Stream processors usually run the same loop for as long as the application is alive:
Reading one event is easy. Producing correct output is harder. Events can arrive out of order, processors can crash, downstream systems can time out, and a late event can change an answer you already published.
Apache Flink is a strong fit for low-latency stateful pipelines, event-time processing, complex event processing, and streaming SQL. Kafka Streams fits services that already live close to Kafka, especially Kafka-to-Kafka transformations.
Spark Structured Streaming works well for teams already using Spark and for pipelines that can share logic between batch and streaming. Beam/Dataflow and managed cloud services are useful when portability or managed operations matter more than direct control over the runtime.
Do not choose a tool by its marketing label. Choose it by fit: state size, latency target, language support, deployment model, connector quality, and how safely it writes results.
Stream processing looks simple in diagrams. In production, it is one of those areas where small details matter. The hard parts come from time, state, and failure.
Events often arrive in a different order than they happened. Mobile clients retry requests. Services buffer messages during deploys. Brokers move data between partitions. Networks delay packets. A producer may write event 10:00:03 before event 10:00:01 reaches the stream.
This is why stream processors separate three clocks:
For analytics and billing, event time is usually the right choice. For operational alerts, processing time may be good enough because freshness matters more than perfect historical placement.
A late event is an event that belongs to a time window whose result may already have been published.
Trace the example above. The window 10:00 - 10:05 closes once the watermark passes 10:05. At 10:06, it publishes a total of $500. At 10:07, a late event arrives with event time 10:03 and amount $79. It belongs to a window that already published. Now the system has to choose what to do:
$500 stays as is, which is wrong by $79 but cheap and simple.$579 instead of $500. Downstream consumers must be able to handle the changed value.10:07, so the $79 would be included the first time. The trade-off is slower results for everyone.There is no free option. Each choice trades off simplicity, completeness, latency, and how much correction logic downstream systems need.
Watermarks are the usual way to decide when a window is complete enough to publish. A watermark is the processor's best guess that it has seen the events before a certain event time. It is a trade-off, not a guarantee. Aggressive watermarks give faster results but create more late events. Conservative watermarks wait longer and usually produce more complete results.
Most useful stream jobs are stateful. That means the job must remember something from earlier events. Counting purchases per user, detecting repeated login failures, joining clicks with sessions, deduplicating retries, and computing rolling model features all need that memory.
State introduces real engineering work. It must be split across machines so the job can scale, checkpointed so a crash does not reset the calculation, expired or compacted so it does not grow forever, and restored quickly enough after failures.
In AI systems, this matters for online features. A model may need "number of failed payments in the last 10 minutes" or "products viewed in the current session." Those features are useful only if the stream processor keeps them correct through retries, deploys, and partition movement.
Processing guarantees are usually described with three phrases: at-most-once, at-least-once, and exactly-once.
At-most-once processing can lose events because an event may be processed zero or one time. At-least-once processing avoids loss, but it can create duplicates. Exactly-once processing means the result is applied once for a defined set of inputs and outputs. It requires careful agreement between the processor and the destination.
The phrase "exactly-once" is easy to misuse. A streaming engine can often provide exactly-once state updates inside the engine. It can sometimes provide exactly-once writes to supported destinations. It cannot magically make every external API exactly-once.
If your stream job calls a payment gateway, sends an email, or invokes a model endpoint with side effects, you still need practical safeguards: idempotency keys, deduplication, transactional writes, or compensation logic.
Instead of asking whether the engine supports exactly-once, ask:
If this job crashes after processing an event but before or during output, what visible effect can happen downstream?
That question gets you closer to the real failure mode than the label on the engine.
Batch and stream processing differ in more than speed. They make different assumptions about latency, input data, and how your code should behave. This section compares those differences and shows where shared APIs can help.
Batch processing optimizes for efficient work over many records. Stream processing optimizes for fast decisions.
This table compares the factors that usually decide between them.
| Metric | Batch | Stream |
|---|---|---|
| Time to first result | Minutes to hours | Milliseconds to seconds |
| Cost per record | Often lower for large workloads | Often higher because work is continuous |
| Resource pattern | Bursty or scheduled | Always running |
| Backfills | Natural fit | Possible through replay, but harder to run safely |
| Debugging | Easier to reproduce from fixed input | Harder because time, state, and ordering matter |
| Best default | Historical computation and correction jobs | Operational decisions that lose value if delayed |
Batch jobs work on fixed-size, or bounded, datasets. For the chosen period, the input can be complete before the job starts. The job can sort it, split it differently, and scan it more than once. Late data is usually handled by rerunning the job or widening the input window. Output often replaces or appends partitions and tables.
Streaming jobs work on unbounded datasets. Input is always still arriving. The processor must tolerate out-of-order events, decide what to do with late data, and rely on replay from durable logs when reprocessing is needed. Output is usually incremental: updates, events, or continuously refreshed state.
Batch code can assume the input has an end:
Stream code must define how to group a never-ending input into useful slices:
The window is not just an implementation detail. It is part of the product behavior. A "five-minute error rate" and an "hourly error count" answer different operational questions.
Newer systems often expose batch and streaming through similar APIs. Spark Structured Streaming uses Spark's DataFrame model for streaming workloads, while Flink supports both bounded and unbounded streams. This makes the tools easier to learn and can help teams reuse code.
The core design differences still matter. A streaming job still needs decisions about event time, watermarks, how long to keep state, replay, and what happens when output is written twice. A batch job still needs decisions about how data is split up, when jobs run, data quality, and backfills.
Micro-batch processing groups incoming events into small batches, often a few seconds long, and processes each group like a mini batch job.
Micro-batch is often a good trade-off when the business needs fresh data but not per-event latency. A dashboard that updates every 10 seconds, a warehouse table that updates every minute, or a feature pipeline that can tolerate short delays may not need a true event-at-a-time engine.
Spark Structured Streaming commonly uses this model. The benefit is familiarity: many transformations look like batch transformations, and the engine can process each trigger as a small job. The cost is a built-in minimum delay and a less natural fit for workloads that need very low latency or fine-grained event-time behavior.
Start with the cost of waiting.
Choose batch when the result is only needed after a reporting period closes, the workload scans a lot of historical data, or correctness matters more than speed. Batch is also a strong fit for backfills, audits, reconciliation, training, embedding generation, expensive joins, and global aggregation.
Choose stream processing when a delayed decision loses business value or creates risk. Streaming is the better fit when the system must react while users, devices, or transactions are active. It also fits systems that maintain live state, publish incremental events, or process naturally event-shaped data such as clicks, transactions, telemetry, and database changes.
Most production systems land here. They use streams for immediate decisions and batch for correction, audits, and historical truth. They train models in batch while updating online features from streams. They publish operational dashboards from streams and rebuild indexes from the source of truth in batch.
This combination is not a failure of architecture. It is usually the mature design. Streams give fast reaction. Batch gives durable correction.
Batch processing works on bounded data. It is the right default for large historical jobs, offline analytics, training pipelines, backfills, billing, and reconciliation.
Stream processing works on unbounded data. It is the right default when the system must react while events are still fresh, such as fraud detection, alerting, live dashboards, online recommendations, IoT, CDC, and operational workflows.
Micro-batch sits between them, giving near-real-time results for workloads that tolerate seconds of latency and benefit from a batch-like execution model.
Start with freshness and correctness. How fresh must the result be? How wrong can it be, and for how long? Answer those questions first, and the architecture usually becomes clear.
10 quizzes