Batch, Streaming, and Real-Time Serving Trade-offs Questions
Reasoning about when to use batch, micro-batch, or continuous streaming and how to serve low-latency analytics: latency, cost, complexity, and correctness trade-offs; lambda vs kappa architectures; and reprocessing semantics. Covers real-time aggregation, freshness vs consistency trade-offs, and reconciling streaming results with batch ground truth, including geospatial and high-throughput real-time workloads under eventual consistency. The data-systems judgment topic for choosing and reconciling batch versus real-time approaches, distinct from the hands-on streaming transport itself.
A product team requests near-real-time personalization requiring sub-100ms reads and 1,000 writes/sec. Decide between a stateful streaming architecture and a micro-batch near-real-time approach: compare latency, cost, operational complexity, and developer velocity, and propose a recommended architecture with a migration plan from whatever exists today.
Sample Answer
Direct answer
At sub-100ms reads and 1,000 writes/sec for personalization, a micro-batch approach almost certainly cannot meet the latency bar (even a very tight micro-batch adds tens to hundreds of milliseconds of batching delay before a write is even visible), so this points toward a stateful streaming architecture, with the real design work being how to serve those sub-100ms reads cheaply, not whether streaming is required.
Structured elaboration
Why micro-batch struggles here: a micro-batch interval tight enough to keep end-to-end latency under 100ms (accounting for batch collection time plus processing time) starts to lose most of micro-batching's efficiency advantage, since you're now paying near-continuous compute anyway, without the operational simplicity batch normally offers. At that point you've built something that behaves like streaming but without streaming's tooling for state and exactly-once handling, which is often a worse trade than just using a real streaming engine.
Latency: streaming wins clearly; a stateful stream processor updating a low-latency key-value store as writes arrive can support sub-100ms reads if the read path is a simple point lookup, not a recomputation.
Cost: streaming's always-on compute and (likely) resident low-latency storage cost more than a batch approach would, but at only 1,000 writes/sec, this is a modest-scale system either way, so the absolute cost difference is unlikely to be the deciding factor here, the latency requirement is.
Operational complexity: real, and worth naming honestly: state management, checkpointing, and monitoring for a stream-processing system require different skills than a batch pipeline, and this is a genuine cost of the recommendation, not something to gloss over.
Developer velocity: initially slower to build (more moving parts to get right), but once the pattern is established, adding new personalization signals to an existing streaming pipeline is usually incremental, versus repeatedly re-tuning batch intervals as latency requirements tighten over time.
Worked example
Suppose the current system is a batch job that recomputes personalization signals hourly. The migration plan: (1) stand up a stream processor that consumes the same event source and computes the personalization state incrementally, writing to a low-latency store (Redis or DynamoDB-style key-value store) sized for the 1,000 writes/sec and sub-100ms read requirement; (2) run it in shadow, comparing its computed values against the batch job's hourly output for the same users, to validate correctness before it serves any real reads; (3) cut over reads to the new store behind a feature flag, monitoring read latency directly (not just throughput) to confirm the sub-100ms bar holds under real production load, not just in testing; (4) once validated, retire the hourly batch job, or repurpose it as a periodic correctness-reconciliation check rather than the primary compute path.
Trade-offs and pitfalls
The common mistake is trying to squeeze micro-batch tighter and tighter to chase a latency target it wasn't designed for, rather than recognizing the 100ms bar as a genuine architectural signal to move to streaming; there's a point (well before 100ms) where shrinking the batch interval stops buying meaningful latency improvement and just adds overhead. The other mistake is under-investing in the shadow-validation step in the migration plan, since a stateful streaming system that's subtly wrong (a race condition in how state updates, an edge case in cold-start behavior for a brand-new user with no prior state) is much harder to debug after it's serving live personalization decisions than to catch in a shadow comparison against the known-correct batch baseline.
Explain the real differences between batch processing and stream processing for a production data platform: latency, throughput, cost, operational complexity, and correctness. Give one concrete workload that clearly favors each approach, and describe a scenario where a hybrid of the two is the right call.
Sample Answer
Direct answer
Batch and streaming are two ways of answering the same question (what does the data say right now) at different points on the latency/cost/complexity curve. Batch reads a large accumulated chunk on a schedule; streaming processes each event as it arrives. Pick batch by default and reach for streaming only when a specific business decision genuinely needs data fresher than the next scheduled run can provide.
Structured elaboration
Latency. Batch is minutes to a day (whatever the schedule is); streaming is sub-second to a few seconds, bounded mainly by how long you wait for late data (the watermark).
Throughput. Batch amortizes overhead across a huge chunk, so it is usually the cheaper way to move the same total volume of data. Streaming pays a small per-event tax (serialization, network hops, state lookups) on every single record, so the same total throughput costs more compute.
Cost. A batch job runs, finishes, and releases its compute. A streaming job holds compute (and often memory-resident state) 24/7 whether or not there's a burst of traffic, so streaming infrastructure has a real always-on cost floor that batch does not.
Operational complexity. Batch failure recovery is simple: rerun the job. Streaming failure recovery has to reason about partial state, checkpoints, exactly-once vs at-least-once delivery, and consumer lag, which means more moving parts, more monitoring surface, and a team that has to understand event-time semantics, not just SQL.
Correctness. Batch naturally sees all the data for a period before computing anything, so late-arriving records are simply part of the input. Streaming has to make an explicit decision about how long to wait for late data (allowed lateness) before it emits a result, which means a streaming aggregate can legitimately differ from the eventual batch recompute of the same period.
| Axis | Batch | Streaming |
|---|---|---|
| Latency | minutes to a day | sub-second to seconds |
| Throughput cost per unit volume | lower (amortized) | higher (per-event overhead) |
| Infra cost floor | zero between runs | always-on |
| Ops complexity | low (rerun on failure) | higher (state, checkpoints, lag) |
| Correctness model | sees everything before computing | must decide how long to wait for late data |
Worked example
A nightly-refreshed revenue dashboard is a clean batch case: the business consumes it once a day, a few hours of latency is invisible to the user, and a failed run just reruns. A fraud-detection system that has to block a card swipe before it completes is a clean streaming case: by the time a batch job would even start, the transaction has already succeeded or failed. A hybrid shows up constantly in practice: a company might run streaming only for the handful of metrics that trigger pages or block a transaction, and leave everything else (the other 90% of reporting) on batch, because paying the always-on cost and operational overhead of streaming for a dashboard nobody checks more than once a day has no payoff.
Trade-offs and pitfalls
The most common mistake is treating this as a technology choice instead of a latency-requirement choice: teams reach for Kafka and Flink because streaming sounds more modern, then discover they've taken on 24/7 operational burden for data nobody looks at more than once a day. The second most common mistake is the opposite: assuming batch is always simpler, when a batch job that has grown large enough to blow its nightly window is itself an operational risk. The right first question is always "what decision does this data drive, and how fresh does it actually need to be to drive that decision correctly," not "which technology is state of the art."
A team needs both retrainable ML models (which want reproducible, accurate historical data) and low-latency online scoring. Which would you recommend, Lambda or Kappa, and why? Sketch how you would migrate from the other architecture with minimal risk, and describe how you'd keep the online features and the periodic batch snapshots used for training reconciled with each other.
Sample Answer
Direct answer
For a team that needs both retrainable models on reproducible historical data and low-latency online scoring, I'd lean toward a Kappa-style single streaming codebase with an explicit batch snapshot layer bolted on for training, rather than a full Lambda split, because the two consumers (the online scorer and the training pipeline) actually want the same underlying feature-computation logic, and duplicating that logic in a full Lambda setup is where ML teams most often introduce training-serving skew.
Structured elaboration
The key insight is that "low-latency scoring" and "reproducible training data" don't need two different processing engines, they need one feature-computation codebase and two different consumption patterns of its output: a live path for scoring, and periodic durable snapshots of the same computed features for training.
If choosing Kappa-leaning: run the feature computation as a single streaming job (Flink or Kafka Streams) that both serves online reads and periodically materializes a snapshot of feature values to durable storage (a feature store's offline layer or a warehouse table) at a fixed cadence. Training reads the snapshots; serving reads the live streaming state. Because both paths run the same code, a definition change (say, a new bucketing rule for a categorical feature) automatically applies to both, which is exactly the alignment you want.
Migration steps from a Lambda-style setup: (1) identify where the batch and speed layer logic has already diverged, and reconcile them into one shared definition first, before touching infrastructure; (2) stand up the streaming feature-computation job so it can both serve online reads and write periodic snapshots, running it in shadow (not yet serving) against production traffic; (3) validate that the streaming job's snapshots match the batch layer's historical output for a trailing window, within an agreed tolerance; (4) cut serving traffic over, keep the old batch layer running in parallel for a defined bake period as a fallback; (5) once validated, deprecate the separate batch feature pipeline.
Keeping online features and batch snapshots reconciled: version every feature definition (not just the values), so an offline snapshot can be tagged with exactly which code version produced it; run a scheduled comparison job that samples recent online feature values against what the batch snapshot computed for the same entities and time window, and alert if they diverge past a tolerance (some drift is expected from timing, not necessarily a bug, so the tolerance matters).
Worked example
A personalization model retrains nightly on nightly feature snapshots but scores online with sub-second freshness. Before migration, the team has two implementations of "user's 7-day click rate": a Spark job for training data and a Flink job for serving, and they've already seen the two disagree by a few percent because of a rounding difference in a time-window boundary. After migrating to the shared streaming codebase, the same Flink job computes the click rate for both serving and, once a day, snapshots it to the training table, so the discrepancy is structurally impossible rather than something the team has to keep re-verifying.
Trade-offs and pitfalls
The risk in this approach is treating the snapshot cadence as free: if training needs feature values reproducible for a specific historical instant (for point-in-time correctness, avoiding label leakage), the snapshot job has to be built with that discipline from day one, not bolted on later, since a naive "just query current state" snapshot will leak future information into training data. The other pitfall is skipping the shadow-validation step under time pressure; training-serving skew introduced silently during a rushed migration is far more expensive to debug after the fact than the extra week the validation step costs upfront.
Design a near-real-time feature store that supports both offline batch features and online features with a 1-minute freshness target. How do you reconcile the two, so a value computed by the nightly batch job and the same value computed by the online path don't silently drift apart, and how do you version features as the reconciliation logic changes?
Sample Answer
Direct answer
The way to keep an offline batch-computed value and an online streaming-computed value from silently drifting apart is to make them provably the same computation, not two independently-tuned approximations of the same idea, by sharing the feature definition's code (or at minimum its exact specification) between both paths and continuously measuring the gap between them rather than assuming it's zero.
Structured elaboration
Reconciliation mechanism: implement the feature's transformation logic once, in a form that both the offline batch job and the online serving path can execute (a shared library, or a framework that compiles one definition to both a batch and a streaming runner). This removes the most common cause of drift, which is two engineers implementing "the same" feature slightly differently (different time-window boundary conventions, different null-handling, different rounding).
Feature versioning: attach a version identifier to every feature definition, and store that version alongside every computed value, both online and in the offline snapshot table. This lets you answer "which exact logic produced this number" months later, and lets you roll out a definition change safely (both paths read the new version's code, and old data stays tagged with the old version rather than being silently reinterpreted).
Measuring drift, not assuming it away: run a scheduled job that samples recent entities, pulls both the online-computed value and what the offline batch snapshot computed for the same entity and time, and reports the distribution of differences. Some non-zero drift is expected and fine (timing differences mean the online value reflects slightly more recent data than the batch snapshot captured), but the monitoring job should alert if the drift distribution shifts meaningfully, which usually signals a real bug (a definition mismatch, a bad deploy) rather than expected timing noise.
Handling the reconciliation logic changing over time: when the feature definition itself changes (a new bucketing rule, say), version the change explicitly, backfill historical offline snapshots under the new version if training needs consistent history, and don't silently apply the new definition to old data without re-versioning it, since that would make the drift-monitoring job (and any model trained on the old data) unable to tell what actually changed.
Worked example
A "user's 7-day purchase count" feature is defined once, in a shared library, and compiled to run both inside the online Flink job (serving reads) and the nightly batch snapshot job (training reads). The drift-monitoring job samples 10,000 users daily, compares online vs. snapshot values for the same user and day, and typically finds a small, explainable gap (the online value sometimes includes a purchase from the last few minutes that the prior night's snapshot didn't yet have). When a deploy accidentally changes the online path's window boundary from inclusive to exclusive, the drift-monitoring job's next run shows a sudden, systematic shift in the difference distribution (not just noise), which is exactly the signal that catches the bug before it silently degrades whatever model consumes the feature.
Trade-offs and pitfalls
The most common mistake is building the online and offline computations as two separate implementations "because they're different systems anyway" and trusting code review to keep them aligned; code review reliably misses subtle semantic differences (an inclusive versus exclusive window boundary looks identical in two different codebases written by two different people). The second mistake is treating any measured drift as automatically a bug and chasing it to zero; some drift is structurally expected from timing alone, and the useful signal is a change in the drift distribution, not its mere existence.
Compare batch processing and stream processing as general models, then bring Lambda and Kappa architecture into the comparison. For a concrete analytics workflow of your choosing, walk through why you would pick pure batch, pure streaming, Lambda, or Kappa.
Sample Answer
Direct answer
For any given analytics workflow, the choice isn't a single spectrum from batch to streaming; it's two separate decisions layered on top of each other: how fresh does this need to be (which points you toward batch or streaming), and, if you need streaming, do you also need a batch backstop for correctness (which is the Lambda-vs-Kappa question).
Structured elaboration
Start with the freshness requirement. If the consumer can tolerate minutes-to-a-day of latency, pure batch wins on cost and operational simplicity; there's nothing to gain from adding streaming machinery. If the consumer needs sub-second-to-seconds latency, you need some form of streaming, full stop, because no amount of clever batch scheduling gets you there.
Once you've established you need streaming, the second decision is whether a single streaming codepath (Kappa) is trustworthy enough on its own, or whether you want a separate, deterministic batch recomputation as a correctness backstop (Lambda). That decision usually turns on: how expensive is being wrong (financial reporting wants a backstop; a live view-count doesn't), and how cheap is full-history replay in your streaming stack (if replay is fast and reliable, Kappa's single codepath is enough; if it isn't, or if a regulator wants a simple, deterministic recompute story, add the Lambda-style batch layer).
Worked example
Take a concrete workflow: computing daily active users for a product dashboard, with a secondary need for a live "users online right now" counter.
- Pure batch fits the daily-active-users number: it's consumed once a day, needs to be exactly right, and a nightly job scanning the day's log is both cheap and simple.
- Pure streaming fits the live counter: it needs to update within seconds and an occasional off-by-a-few-users error during a brief network blip is not a business problem.
- Kappa would fit if this company later wants daily active users computed from the same streaming pipeline as the live counter, and their streaming engine can cheaply replay a day's worth of events to recompute that day's number deterministically, avoiding a second batch codebase.
- Lambda would fit if daily active users feeds into a revenue-attribution or billing calculation where the company genuinely wants a batch recompute as an audit trail, independent of whatever the streaming engine's live counter reported.
Trade-offs and pitfalls
The pitfall in this kind of question is answering "it depends" without giving the two-step decision structure that makes it not ambiguous: freshness requirement first, correctness-backstop need second. Answering with just "streaming is for real-time and batch is for reports" skips the actual judgment call, which is when a single streaming codebase is trustworthy enough to be the only source of truth, and when it isn't.
Unlock Full Question Bank
Get access to all 9 Batch, Streaming, and Real-Time Serving Trade-offs interview questions and detailed answers.
Sign in to ContinueJoin thousands of developers preparing for their dream job.