In a 2021 streaming-pipeline case study, Uber reported 34,000 writes per second with a batch size of 50, 37,000 with 100, and 38,000 with 200. Doubling the batch twice delivered progressively smaller gains in that configuration. Uber's engineering account is a useful opening for a staff engineer interview: a tuning knob becomes meaningful only when you explain the bottleneck, the measurement, and the cost.
A Kafka-and-Flink diagram gives you components. A defensible event-streaming design gives you contracts: what stays ordered, how long results remain revisable, which failures produce retries, and how the system catches up after falling behind. This guide uses an illustrative marketplace activity pipeline to practice those decisions. The quantitative worked examples are assumptions for reasoning, not production benchmarks or hiring statistics.
1. Define the contract before choosing the pipeline
Begin with the output someone will use. For this example, suppose a marketplace needs a dashboard showing completed purchases per merchant in five-minute event-time windows. Propose an initial freshness target, ask whether corrections are acceptable, and identify which downstream operations have irreversible effects. An analytics correction and a second customer charge require very different handling.
Write four questions next to the architecture: Does ordering apply per purchase or per merchant? What identifies a duplicate? How long can devices be offline? Who owns the authoritative purchase state? Treat the answers as design inputs. Kafka records have keys, values, timestamps, and metadata; its introduction explains the event model. Those fields do not decide your business rules for you.
Give the interviewer an explicit starting point
A useful opening is: “I will preserve purchase-level transitions, publish provisional merchant aggregates, and support corrections. I will use an event ID for deduplication and a producer-assigned purchase version for transition validation. Before sizing, I want the peak rate, key distribution, payload size, and recovery target.”
Then sketch producers, a durable event log, a stateful processor, and a serving store. Keep the raw-event path available for rebuilding derived views. Kafka permits repeated consumption within configured retention, as documented in its topic retention model. Specify a proposed retention period and explain how you would validate it against the longest required replay. Do not promise an unlimited recovery window.
2. Preserve the ordering you need, then test the hottest key
Kafka's ordering guarantee applies within a topic partition. With consistent keyed routing, events for the same key reach the same partition; this does not create a total order across the topic. The boundary is explicit in Kafka's partitioning documentation. State it before proposing parallel consumers.
For purchase transitions, start with purchase_id. Validate the purchase version, deduplicate, and emit accepted changes. Repartition that output by merchant_id for merchant aggregation. This separates two proposed invariants: purchase transitions must respect the domain's version rules, while counts can combine accepted events. A timestamp alone should not be your proof that a transition is valid.
A popular merchant exposes the scaling boundary
Illustrative arithmetic: suppose one merchant produces 20,000 accepted events per second, while one aggregation worker sustainably handles 5,000. Adding workers for other merchants leaves this key overloaded. To distribute its work, propose partial aggregates keyed by merchant and shard, followed by a merge. For a count or sum, explain how the partial results combine and how duplicates affect them.
For a state machine that must apply every merchant-level transition serially, sharding changes the ordering contract. Ask whether the domain permits a narrower unit of serialization. Otherwise, admit the capacity limit and propose admission control or a different implementation. The interview answer should make that limit visible instead of hiding it behind a larger partition count.
Changing partition count also deserves a migration plan. Kafka warns that existing key-to-partition mapping can change when partitions are added; see its topic modification guidance. Propose versioned routing, draining, or an explicit cutover appropriate to the contract.
Finally, check retries. Kafka documents possible producer reordering when idempotence is disabled and multiple requests are in flight. Its producer configuration reference describes the compatible idempotence settings. Preserve ordered application of records after consumption, too: do not assume a concurrent worker pool completes in read order.
3. Separate event time, processing time, and watermark progress
Ask which clock the dashboard means. A purchase made before a device loses connectivity should usually belong to the window of the purchase, not the window when a processor eventually receives it. Flink's windowing introduction distinguishes event time from processing time and explains why delays matter to those semantics.
A watermark expresses progress in event time. It does not guarantee that an offline device will never send an older event. Flink's event-time explanation explicitly discusses arrivals that violate watermark expectations. Treat your watermark strategy as a declared assumption about disorder, paired with a policy for exceptions.
Walk through one timeline
Illustrative example: events arrive with timestamps 12:00:08, 12:00:12, and 12:00:09. With a proposed ten-second disorder bound, describe progress as approximately the largest observed event timestamp minus that bound; use the framework's precise boundary behavior in implementation. Flink provides a bounded-out-of-orderness strategy in its watermark generation documentation. Ask whether observed timestamp disorder supports your proposed bound.
Now make one source partition quiet. Downstream watermark progress can be constrained by the minimum input watermark. Flink supports marking idle inputs so they stop holding progress back, as described in its idle-source guidance. Choose the timeout deliberately and test what happens when that partition resumes with old records.
For inputs advancing at very different speeds, consider watermark alignment to limit how far fast inputs run ahead. Explain the proposed tradeoff: constrain fast-source progress to control downstream buffering. You should distinguish this deliberate throttling from an unexplained stall.
4. Make late data a product decision
Separate the delay before an initial window result from the period during which it may change. Flink's event-time windows support allowed lateness, which retains window state beyond the window boundary; a late arrival may trigger an updated result. Its window documentation also specifies a default allowed lateness of zero.
For the illustrative dashboard, propose a provisional result followed by corrections for a bounded interval. Give each aggregate an identity such as merchant, window start, and calculation version. Require the sink to apply a newer revision over an older one. Verify that retries and replay cannot replace a corrected count with a stale count.
Window results emitted again after late arrivals represent updates to a prior computation, according to Flink's late-firing guidance. Explain whether the sink accepts full replacement values or deltas. In a proposed delta design, include deduplication of the correction itself. “We support late events” leaves these consequential choices unanswered.
Define what happens after the correction horizon
Flink can expose discarded late data through a late-data side output. Propose an audited correction workflow or a rebuild path for those records. Set ownership, retention, and an alert for growing volume. Avoid describing a side stream as resolution when nobody consumes it.
Measure event delay distributions, correction volume, and retained state before extending the horizon. Ask the interviewer whether a day-old purchase must revise a live dashboard or only a historical report. That answer helps decide which state belongs in the online processor and which can be reconstructed elsewhere.
Practice the tradeoff out loud
Use Interview Copilot to prepare system design questions, then rehearse a streaming answer that states its ordering boundary, late-data policy, and recovery assumptions.
Start your interview preparation5. Diagnose lag and backpressure with different measurements
Kafka consumer lag and Flink backpressure describe different parts of the problem. Kafka exposes per-partition record lag and a maximum lag metric; its monitoring reference notes that consumer lag metrics use the current position rather than the committed offset. State which offset your dashboard measures.
Flink exposes time spent busy, idle, and backpressured. Backpressure is identified through output-buffer availability in its task performance documentation. A worker blocked downstream should not automatically trigger the same response as a worker doing expensive computation.
Follow a hypothesis through the whole path
Suppose lag grows while the sink's request latency increases. Inspect the sink's retries, write limits, and queue occupancy; then compare upstream backpressure and busy time. Suppose only one partition accumulates records instead. Inspect key skew and that partition's assigned work. For a CPU hypothesis, examine the busy operator, serialization, and aggregation cost before adding capacity.
Track end-to-end freshness separately: event creation to visible output, and ingestion to visible output. A processor can read records while their effects remain invisible. Also track watermark delay and the age of the oldest pending event. These proposed views let you explain whether the problem is transport, execution, event-time progress, or publication.
For remote enrichment, Flink's asynchronous I/O API provides bounded concurrency and triggers backpressure when capacity is exhausted. Propose timeouts and retry budgets around the downstream service's capacity. Choose ordered or unordered results according to the operation's semantics. More concurrent requests need a capacity argument, not just an optimistic throughput claim.
Likewise, name the producer overload response. Kafka's buffer configuration describes blocking and eventual failure when records cannot be delivered fast enough. Decide how the application surfaces that failure and which events it may defer or reject.
6. Size for catch-up, skew, and the sink
Use arithmetic to expose assumptions. Illustrative worked example: at 100,000 events per second and 500 payload bytes per event, the logical payload rate is 50,000,000 bytes per second, or 50 MB/s in decimal units. This excludes protocol overhead, compression effects, replicas, indexes, and processor state. Do not present it as a measured broker requirement.
Suppose a ten-minute interruption creates a backlog while arrivals continue at the same rate. That is 100,000 multiplied by 600, or 60 million events. If the recovered pipeline sustains 150,000 events per second end to end, spare capacity is 50,000; draining the backlog takes 1,200 seconds, or twenty minutes. These are illustrative calculations assuming constant rates and no additional restart delay.
Make the recovery objective constrain the proposal. If twenty minutes is unacceptable, identify the additional sustainable capacity required or reduce work per event. Measure capacity at the sink as well as the processor. Check whether a hot partition can catch up independently of the healthy partitions. Aggregate headroom does not establish headroom for each serialized key.
Use benchmarks as evidence for a method
Uber also reported reducing an intermediate message from 451 to 237 bytes and introducing a one-minute deduplication window that reduced an expensive stage to 8,000 messages per second. The team explicitly described the additional minute of latency in the same case study. That supports a method: test less work and smaller messages alongside more workers, while documenting changed semantics.
Present a proposed experiment table verbally: baseline throughput, tail freshness, correction rate, checkpoint duration, resource cost, and the changed parameter. Alter one factor when diagnosing a specific bottleneck. Recheck correctness after optimizations that deduplicate, combine windows, or reorder work. For each successful change, state the workload under which it succeeded and what would make you revisit it.
7. Explain recovery and exactly-once at the boundary
A recovery story needs both processor state and replayable input. Flink's checkpointing documentation describes consistent state snapshots and requires enabling checkpointing. Specify durable checkpoint storage, monitor completion, and test restoration. A configured interval is a proposal; the most recent successful checkpoint is the recovery evidence.
For an exactly-once Kafka sink, Flink commits output transactions on checkpoints, and consumers must read committed data. Consequently, output visibility waits for a checkpoint; see the Kafka connector's delivery guarantees. Include that publication delay in the freshness budget. Check transaction timeouts against worst-case checkpoint and restart duration.
For a database or external API, name the mechanism that couples replay to output. Kafka's delivery-semantics discussion explains the need to coordinate consumer position and externally stored results. Propose an atomic write with an offset where appropriate, or an idempotent operation whose duplicate behavior you can demonstrate. For irreversible effects, ask how the external service records idempotency keys.
Design a rebuild separately from routine restart
For the example, rebuild into a versioned output namespace and compare counts before changing readers. Replay historical events with historical reference data or a declared version of enrichment rules. Otherwise, explicitly call the result a recalculation under current rules. Budget replay so it does not overwhelm the live sink.
Under severe backpressure, Flink's unaligned checkpoints can include buffered in-flight data to improve checkpoint progress. Evaluate checkpoint size, storage traffic, and restore behavior. This addresses snapshot progress; your design still needs enough sustainable capacity to drain the backlog.
8. Keep schema evolution compatible with the replay promise
A new consumer may need to understand records produced long before its deployment. Confluent distinguishes backward compatibility against the latest schema from backward-transitive compatibility against all prior registered schemas. Choose compatibility according to the history you promise to replay, and test representative old records.
For Avro, a reader can use a field default when older writer data lacks that field; missing it without a default causes a resolution error under the Avro schema-resolution rules. Explain what the default means. A syntactically compatible value can still misrepresent the business event.
Stream-record compatibility and saved-state compatibility need separate review. Flink's state schema documentation does not support evolution of key structure. Its savepoint guidance recommends stable operator IDs for mapping state during restoration.
Propose a rollout sequence: verify old-record decoding, restore representative state, compare derived outputs, and retain a tested rollback route. Under backward compatibility, upgrade consumers before publishing the new record format, consistent with Confluent's client upgrade guidance. If a migration changes business meaning, describe that change independently of serialization.
9. Rehearse decisions and failure injections
Practice a concise design narrative: “I key raw events by purchase, validate versions, and repartition accepted events for merchant aggregation. I publish provisional windows with a bounded correction policy. I measure partition lag, output freshness, and operator backpressure separately. Recovery restores state and replays input; sink retries preserve aggregate revisions.” Then let the interviewer change an assumption.
Use four drills: one merchant receives most traffic; a quiet partition resumes with old events; the sink becomes slow; an old schema appears during replay. For each, state the affected invariant, the measurement that reveals the problem, the intervention, and its cost. Avoid reciting every configuration option. Explain why the proposed change fits this failure.
Prepare through Interview Copilot's system design question workflow, and ask for follow-ups about hot keys, watermark stalls, correction writes, and replay. Evaluate your rehearsal against the source contracts above. Prefer an answer that exposes uncertainty and proposes a measurement to resolve it over one that claims universal throughput or perfect ordering.
The strongest streaming design leaves a clear operational promise: who may see a provisional answer, how it gets corrected, and what survives a failure. End your interview answer with the unresolved decision and the experiment you would run first. That turns a component diagram into an engineering plan.
Prepare your next staff engineer interview
Build practice questions with Interview Copilot and rehearse the assumptions, failure scenarios, and measurable tradeoffs behind your event-streaming design.
Create your accountSources & References
Primary sources reviewed October 1, 2026. Kafka configuration statements refer to the linked 4.1 documentation; verify settings for the version in your interview scenario. Uber's figures describe its 2021 workload, not a general performance guarantee.
- Uber Engineering: Building Scalable Streaming Pipelines for Near Real-Time Features
- Apache Kafka: Introduction, Events, Topics, and Partitions
- Apache Kafka: Basic Operations and Topic Modification
- Apache Kafka: Producer Configuration
- Apache Flink: Introducing Stream Windows
- Apache Flink: Event Time and Watermarks
- Apache Flink: Generating Watermarks, Idleness, and Alignment
- Apache Flink: Windows, Allowed Lateness, and Late Outputs
- Apache Kafka: Monitoring and Consumer Lag Metrics
- Apache Flink: Monitoring Back Pressure
- Apache Flink: Asynchronous I/O
- Apache Flink: Checkpointing
- Apache Flink: Kafka Connector and Delivery Guarantees
- Apache Kafka: Design and Delivery Semantics
- Confluent: Schema Evolution, Compatibility, and Client Upgrades
- Apache Avro: Schema Resolution
- Apache Flink: State Schema Evolution
- Apache Flink: Savepoints and Operator IDs