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 analytics dashboard must be updated every 10 minutes and serve thousands of users. Compare three architectures: (A) pure batch with 10-minute micro-batches, (B) a streaming engine, and (C) hybrid (CDC plus periodic batch backfills). For each, discuss cost, latency, complexity, and operational burden, and pick one with justification.
Sample Answer
Direct answer
For a dashboard that needs a 10-minute refresh and serves thousands of users, I'd pick option (A), pure batch with 10-minute micro-batches, because the freshness bar is well within micro-batch's comfortable range and it avoids paying for always-on streaming infrastructure that this workload doesn't actually need; I'd reserve (B) or (C) for a tighter latency bar or a genuinely mixed-freshness requirement.
Structured elaboration
(A) Pure batch, 10-minute micro-batches: cost is the lowest of the three, since compute only runs for the duration of each micro-batch job, not continuously. Latency is bounded by the batch interval plus run time, comfortably meeting a 10-minute bar if the job itself takes a couple of minutes. Complexity is the lowest: standard scheduled-job tooling, straightforward failure recovery (rerun the batch). Operational burden is light: no stream-processing expertise required on the team, no state-management or watermark tuning.
(B) Streaming engine: cost is higher (always-on compute and, likely, resident state), for a latency improvement (sub-minute) the stated requirement doesn't ask for. Complexity and operational burden both rise meaningfully: the team now owns checkpointing, backpressure, and event-time semantics for a workload that didn't need sub-10-minute freshness in the first place. This option only pays for itself if the 10-minute figure understates the real requirement (see the follow-up question) or is expected to tighten soon.
(C) Hybrid, CDC plus periodic batch backfills: cost sits between the other two: you pay for a CDC pipeline (log-based change capture, generally lighter than a full stream processor since it only ships committed changes) on top of the existing batch job, so it's more than (A) alone but usually less than running (B) for every metric. Latency is genuinely mixed rather than a single number: the CDC-fed subset of metrics gets near-real-time freshness (seconds to low minutes), while everything else stays on the 10-minute batch cadence. Complexity rises meaningfully over (A): there are now two data paths to build, test, and reason about, and consumers have to know which panel is on which path. Operational burden follows complexity: the team owns both the batch scheduler and the CDC pipeline's health (replication lag, connector failures), more monitoring surface than (A) alone, though usually less than operating a full stream processor the way (B) requires. This option is worth its cost only if some subset of the dashboard's metrics genuinely need faster-than-10-minute updates (say, an incident-monitoring panel embedded in an otherwise 10-minute dashboard); if the entire dashboard genuinely only needs 10 minutes uniformly, (C) adds this cost and complexity without a matching benefit.
Worked example
An internal ops dashboard for a logistics company needs shipment-status counts refreshed every 10 minutes for thousands of warehouse staff to check periodically. Option (A): a Spark or warehouse-native job runs every 10 minutes, reads the latest partition, recomputes the aggregates, and writes to a serving table; total infrastructure is a scheduler and a compute cluster that only runs a few minutes out of every ten. This comfortably clears the 10-minute bar with meaningful margin, at a fraction of what an always-on Flink cluster serving the same numbers would cost, since the compute is idle (and unbilled, in a serverless/ephemeral setup) most of the time.
Trade-offs and pitfalls
The recurring mistake on this kind of question is picking (B) because streaming is the more sophisticated-sounding answer, without checking whether the stated 10-minute requirement is actually the real one; always confirm whether "10 minutes" is a hard business requirement or a starting ask that will tighten soon, since building (A) now and having to redo the architecture in six months is a real cost too, just a deferred one. The other mistake is reaching for (C) reflexively whenever a requirement mentions "near-real-time," without confirming that only a genuinely distinct subset of metrics needs the faster path; if the whole dashboard shares one freshness requirement, hybrid adds complexity without adding value.
As the lead responsible for the migration, you must decommission a legacy nightly batch ETL and replace it with a stream-first platform. Stakeholders are worried about reliability, cost, and audits. Describe your rollout strategy: migration milestones, the KPIs you'd use to prove success, your communication plan, and the conditions under which you'd trigger a rollback.
Sample Answer
Direct answer
Decommissioning a legacy batch ETL under stakeholder concern about reliability, cost, and audits requires treating the rollout as a trust-building exercise as much as a technical migration: prove reliability and cost with real numbers before asking for the audit trust, sequence milestones so each one reduces risk before the next begins, and make the rollback trigger conditions explicit and agreed in advance, not decided under pressure mid-incident.
Structured elaboration
Migration milestones: (1) stand up the stream-first platform in parallel, validated against the legacy batch output on historical data (parity, at fine granularity, not just aggregate totals); (2) migrate the lowest-risk data domain first (something with low business criticality and low audit sensitivity) to prove the pattern works end to end in production, including its failure modes; (3) migrate progressively riskier/higher-value domains, each gated on the prior migration having run cleanly through at least one full reporting cycle; (4) migrate the highest-stakes, most audit-sensitive domains last, once the team has a proven production track record on the pattern.
KPIs to prove success: data completeness/accuracy (parity against what the legacy batch system would have produced, measured continuously, not just at cutover), latency actually achieved versus the business need it was meant to serve, incident rate and mean-time-to-recovery for the new platform compared to the legacy system's own historical incident rate (so "more reliable" or "less reliable" is an honest, apples-to-apples comparison, not an assumption), and cost, tracked against the projected savings or spend that justified the migration in the first place.
Communication plan: regular, concrete updates to stakeholders using the KPIs above, not just "migration on track" status reports; specifically loop in whoever owns the audit relationship early, since audit concerns are usually really about "can we explain and reproduce this number if asked," which is a requirement the new platform needs to satisfy explicitly (through logging, versioning, and reproducibility), not just imply.
Rollback conditions: define these before migration starts, not during an incident: a data-completeness or accuracy regression past an agreed threshold, an incident rate meaningfully worse than the legacy system's baseline, or an audit finding that the new system's numbers can't be adequately explained or reproduced. Any of these should trigger falling back to the legacy batch pipeline for the affected domain, which is why milestone (1) above, keeping the legacy system intact and runnable, is not optional.
Worked example
For an organization migrating financial-reporting ETL, the first migrated domain might be an internal operational metric (page views, not revenue), low audit sensitivity, low business criticality, used to prove the pattern and catch integration issues cheaply. Only once that's run cleanly for a full month, with parity holding and no incidents worse than the legacy baseline, does the team migrate a domain closer to financial reporting, and the actual revenue-recognition pipeline (the highest audit sensitivity) migrates last, after the team has a track record and the audit team has had visibility into how the new platform's numbers are logged and reproduced.
Trade-offs and pitfalls
The mistake that erodes stakeholder trust fastest is migrating the highest-stakes domain first (often because it's also the domain with the most obvious latency pain, making it tempting to fix first) without a proven track record on lower-stakes data; a single incident on a financially-sensitive pipeline early in the migration can stall the whole program, even if the underlying platform is sound, because trust, once lost with an audit-conscious stakeholder, is expensive to rebuild. The second mistake is defining rollback conditions loosely ("if it doesn't go well") rather than with specific, pre-agreed thresholds, which turns every incident during the migration into a fresh, high-stakes negotiation about whether to roll back, exactly when the organization can least afford that kind of ambiguity.
A pipeline ingests 5 TB/day and needs hourly aggregations. Compare always-on streaming versus hourly micro-batch for this specific workload: cost, latency, and operational complexity. Recommend concrete optimizations (file format, partitioning, compaction, compression) that keep compute and query costs down without missing the freshness bar the business actually needs.
Sample Answer
Direct answer
For 5 TB/day with an hourly freshness requirement, hourly micro-batch is the right default over always-on streaming: you get the freshness the business actually asked for without paying to keep compute resident between hours, and the cost gap is real, not marginal.
Structured elaboration
The freshness bar here is hourly, not sub-second, so the entire benefit streaming exists to provide (low end-to-end latency) is unused: an always-on stream processor would finish computing an hour's aggregate the moment the last relevant event lands, but nobody reads that number until the top of the next hour anyway. What streaming does cost, always, is a resident cluster: compute (and often state) held 24/7 regardless of whether data is flowing.
Micro-batch instead spins up compute, processes the hour's slice, writes the result, and releases the compute, so you only pay for the minutes you're actually crunching data, not the 50+ minutes per hour you're idle. On operational complexity specifically: micro-batch keeps the team on familiar, simple failure recovery (a failed hourly run just reruns from the last good partition), whereas an always-on streaming job adds real operational surface, checkpoints, consumer lag, state backends, that this workload's relaxed freshness bar doesn't buy back any benefit for.
Concrete optimizations that matter more than the batch-vs-stream choice itself:
- File format: land raw as Parquet (columnar, compressed) rather than raw JSON; this cuts both storage footprint and the bytes the hourly job has to scan.
- Partitioning: partition by hour (and a natural key like region or event type if queries filter on it), so the hourly job and any downstream ad-hoc query only touch the slice it needs.
- Compaction: many small files from continuous ingestion kill batch-read performance; compact into fewer, larger files (target roughly 128MB-1GB per file) either at write time or as a periodic housekeeping job.
- Compression: Snappy or Zstd on top of Parquet trades a small CPU cost for a meaningfully smaller scan volume, which usually pays for itself at this data size.
Worked example
Assume the streaming option is a small always-on cluster (8 vCPUs) running 24/7, and the micro-batch option is a bigger ephemeral cluster (32 vCPUs) that only runs for about 10 minutes each hour, at an illustrative $0.05/vCPU-hour:
DAILY_TB = 5.0
HOURS_PER_DAY, DAYS_PER_MONTH = 24, 30
STREAMING_CLUSTER_CORES, CORE_HOUR_COST = 8, 0.05
BATCH_CLUSTER_CORES, BATCH_MINUTES_PER_RUN = 32, 10
streaming_hours_per_month = HOURS_PER_DAY * DAYS_PER_MONTH # 720
streaming_core_hours = STREAMING_CLUSTER_CORES * streaming_hours_per_month # 5,760
streaming_cost = streaming_core_hours * CORE_HOUR_COST # $288.00
batch_runs_per_month = HOURS_PER_DAY * DAYS_PER_MONTH # 720
batch_core_hours = BATCH_CLUSTER_CORES * (BATCH_MINUTES_PER_RUN/60) * batch_runs_per_month # 3,840
batch_cost = batch_core_hours * CORE_HOUR_COST # $192.00
print(f"streaming_core_hours={streaming_core_hours}")
print(f"streaming_cost={streaming_cost:.2f}")
print(f"batch_core_hours={batch_core_hours:.0f}")
print(f"batch_cost={batch_cost:.2f}")
print(f"cost_ratio={streaming_cost/batch_cost:.2f}")
print(f"savings={streaming_cost-batch_cost:.2f}")
time_fraction_pct = (BATCH_MINUTES_PER_RUN/60) * 100
cost_fraction_pct = (batch_core_hours/streaming_core_hours) * 100
idle_fraction_pct = 100 - time_fraction_pct
print(f"time_fraction_pct={time_fraction_pct:.1f}")
print(f"cost_fraction_pct={cost_fraction_pct:.1f}")
print(f"idle_fraction_pct={idle_fraction_pct:.1f}")
Executed output: streaming = 5,760 core-hours -> $288.00/mo; micro-batch = 3,840 core-hours -> $192.00/mo. That's a 1.5x cost ratio in streaming's favor for micro-batch, a $96/month saving in this illustrative sizing. The 16.7% figure (10 of the 60 minutes in each hour) is the batch cluster's time fraction, not its cost fraction: the batch cluster is 4x the size of the streaming one (32 vCPUs vs. 8), so its actual core-hour draw is 4 times 16.7%, that is 66.7%, of what the always-on cluster consumes, which is exactly the ratio of 3,840 to 5,760 core-hours that produces the 1.5x cost gap. A cluster that is 4x bigger but idle 83.3% of the time still costs less than one running continuously at a quarter of the size, but it is the combination of the bigger core count and the shorter run time, not the 16.7% time fraction by itself, that produces the $96 saving. At a real 5 TB/day scale the cluster sizes and $/core-hour will differ from this illustration, but the shape of the trade (pay only for active minutes vs. pay for 24/7 residency) holds regardless of the specific numbers.
Trade-offs and pitfalls
The common mistake is picking streaming because 5 TB/day sounds like it needs "big data" infrastructure. Data volume and latency requirement are independent axes: high volume with a relaxed latency bar is exactly the case micro-batch is built for, and paying an always-on tax for freshness nobody asked for is pure waste. The flip side pitfall: if the business later needs the freshness bar tightened to minutes, don't just shrink the batch interval indefinitely, since per-run overhead (cluster startup, small-file proliferation) stops being a rounding error somewhere around 5-15 minute intervals, and that's the point to seriously evaluate a real streaming engine instead.
Operations wants 1-minute near-real-time dashboards for incident monitoring; finance insists on strict reconciliation and accuracy for financial KPIs. As the lead responsible for the data, design a solution and a negotiation plan that balances speed against accuracy: the technical options (streaming vs micro-batching), a reconciliation pipeline, SLAs for each audience, and how you would get both parties to accept the trade-off.
Sample Answer
Direct answer
The resolution isn't picking one side, it's architecting for both: serve operations a fast, clearly-labeled provisional streaming view for incident monitoring, and keep finance's KPIs on a separately reconciled batch pipeline that becomes the official number, with an explicit, documented reconciliation step connecting the two so nobody is surprised when the fast number and the official number differ slightly.
Structured elaboration
Technical design: run a streaming aggregation for the operational metrics operations needs within a minute, but label its output explicitly as provisional (in the dashboard UI, not just in documentation). Run a separate, slower batch (or micro-batch) pipeline that reconciles late-arriving data and any corrections, and treat that pipeline's output as the source of truth for financial KPIs. The two can share upstream event sources but should be architecturally decoupled: a bug or outage in the fast path should never be able to corrupt the slow, official path.
Reconciliation pipeline: define a fixed reconciliation window (say, T+24 hours) after which the batch numbers are considered final for a given period, and surface any material difference between what the streaming view showed in the moment and what the reconciled batch number turned out to be, so operations can calibrate how much to trust the live view for borderline cases.
SLAs for each audience: operations gets a documented "fast, directionally correct, may be revised" SLA (say, 1-minute freshness, +/- a few percent accuracy); finance gets a documented "accurate, revised as needed, finalized at T+24h" SLA. Writing these down as explicit, different contracts is what actually resolves the conflict, since both sides are now getting what they need instead of one side's need being silently deprioritized.
Negotiation and communication: get both stakeholders in the same conversation rather than mediating between them separately, show them the two-SLA proposal together, and be explicit that this is not a compromise on accuracy for finance or a compromise on speed for operations, it's giving each of them the thing they actually asked for, at the cost of maintaining two pipelines instead of one.
Worked example
An incident-monitoring dashboard shows "orders failing: 42 in the last minute" from the streaming path, while the end-of-day reconciled batch number for that same minute later reads 39 once duplicate retries are deduplicated. Operations acted on the 42 in real time (correctly, since a 3-order discrepancy doesn't change the decision to page someone), and finance's month-end report uses the reconciled 39. Both numbers are "right" for their purpose, and because both audiences were told upfront that this discrepancy is expected and bounded, nobody escalates it as a data-quality bug when they eventually compare the two.
Trade-offs and pitfalls
The pitfall is building this without labeling the provisional numbers clearly in the UI itself, since a fast number that looks identical to a finalized number will eventually get quoted in a context (like an actual financial report) where the discrepancy becomes a real problem, not just an expected one. The other pitfall is skipping the joint conversation and instead building a technical solution first, then explaining it after the fact; the negotiation has to happen before the architecture is finalized, because the two SLAs (freshness bound, accuracy bound) are themselves a negotiated outcome, not a purely technical decision.
You must decide between batch and streaming for two different needs at once: (A) daily aggregated revenue reports consumed by analysts, and (B) real-time fraud alerts that need to fire within 10 seconds. Walk through the trade-offs for each and justify why you would (or would not) reach for the same approach for both.
Sample Answer
Direct answer
These two needs sit at opposite ends of the latency spectrum and should not be forced onto one pipeline: daily revenue reports are a batch problem, real-time fraud alerts are a streaming problem, and trying to serve both from the same infrastructure choice usually means over-paying for one or under-serving the other.
Structured elaboration
For (A), daily aggregated revenue reports: analysts consume this once a day, the numbers need to be complete and auditable (finance will reconcile them against source systems), and a few hours of processing latency is invisible to the consumer. A nightly batch job that waits for the full day's data, recomputes cleanly, and can be rerun if something goes wrong is the right shape: simple failure recovery, lower compute cost per unit of data processed, and no need to reason about partial/late data during the run because by the time it runs, the day is over.
For (B), fraud alerts within 10 seconds: by definition, this decision has to be made before a batch job would even have started. This is not a latency optimization on top of batch, it is a different processing model: a streaming (or at minimum sub-minute micro-batch) pipeline that scores each transaction as it arrives, with a state store holding whatever recent history the model needs (velocity checks, recent device/IP behavior) and an alerting path that can act within the window.
Worked example
Concretely: revenue reporting reads from the same append-only event log as the fraud pipeline, but on a completely separate cadence and infrastructure. The fraud path needs a stateful stream processor (state per card/account, sub-second decisions) and pays 24/7 compute for that state and the always-on stream. The reporting path needs a scheduled job (Airflow-triggered Spark or a warehouse-native transform) that reads yesterday's partition once, and pays only for the run itself, typically a fraction of the fraud path's monthly compute for a similar data volume, because it isn't holding anything resident between runs.
Trade-offs and pitfalls
The trap is assuming one architecture has to serve both because they draw from the same source events. That's a data-modeling question (do both consume the same log, yes), not a processing-model question (do both need the same latency, no). Building the fraud pipeline on top of the revenue pipeline's batch cadence would make fraud detection useless (alerts arrive after the damage is done); building revenue reporting on top of the fraud pipeline's streaming infrastructure would mean paying always-on compute and operational overhead for a report nobody looks at outside business hours, with no benefit, since "more real-time" doesn't make a once-a-day report more correct or more useful.
Unlock Full Question Bank
Get access to all 19 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.