How the interviewer opens it
“Design an ad click aggregator that receives click events at very high volume. Advertisers should be able to query click counts for their ads over time windows in near real time, and we need accurate numbers for billing.”
The prompt is vague on purpose. The first few minutes are yours: narrow it to the core features and agree on the numbers before you draw anything.
What to clarify first
- event contract
- ingestion scale
- read:write mix and skew
- query semantics
- lateness and retries
- latency
- consistency versus availability
- durability and retention
- billing finalization
- scope boundaries
The answers stay with the interviewer. In a SysRound round, Alex answers them as an interviewer would.
Scope of a strong answer
Core requirements
- Durably ingest click events from trusted collectors
- Return per-ad click counts for requested time windows
- Count each logical click once despite retries and replay
- Produce complete, auditable daily counts for billing
Usually out of scope
- Ad selection and auctions
- Fraud detection and attribution
- Unique-user counting
- Pricing, invoicing, and payment collection
- Active-active ingestion across regions
What interviewers probe
- Counting once across retries, crashes, and replay
- Transport retries and processing retries are different duplicate sources. Correct deduplication at ingestion does not prevent a crash from applying the same increment twice to an external serving database.
- Event time, completeness, and closing a bill
- A quiet partition, a delayed collector, and a processing outage can all look like missing clicks. Waiting a fixed amount of wall-clock time does not prove a day's bill is complete.
- A popular ad cannot own one ingestion bottleneck
- Partitioning directly by ad makes queries convenient but sends up to 200,000 events/s for one ad to one state owner. Splitting that work creates another problem: merging partial results without duplicates or excessive state.
- Fast time-window totals without inconsistent rollups
- Long ranges are expensive at minute granularity, but mixing minute, hour, and day totals can double-count intervals or leave higher-level totals stale after late clicks.
Common mistakes
- Equating an HTTP request or log record with one unique click and ignoring producer retries.
- Claiming end-to-end exactly-once because the message broker has transactions.
- Partitioning every stage by ad_id and ignoring the hottest ad.
- Keeping all dedup IDs in a small Redis instance without calculating cardinality or retention.
- Using processing-time windows or dropping late events without defining billing consequences.
- Treating the dashboard database as the only billing source, with no immutable inputs, completeness checks, or reconciliation.
The bar by level
- Senior (L5/E5)
- Quantifies throughput and dedup state, handles hot ads with preaggregation, explains processing and sink retry semantics, and designs late-event correction plus efficient range queries. Defines a concrete reconciliation and finalization process rather than relying on a timer or the stream framework's guarantees.
- Staff (L6+/E6+)
- Makes correctness boundaries explicit across collector, log, state, sink, archive, and billing publication. Connects eligibility rules, dedup retention, checkpoints, and historical replay; distinguishes freshness from provable completeness. Designs isolated repair and publication workflows, evaluates state/archive costs, and explains which guarantees are sacrificed during outages without risking silent billing errors.