Design Ad Click Aggregator


Patterns, Technologies, and Concepts

Ad Click Aggregator

Key Takeaways

Requirements

You demonstrated strong system design instincts from the start, covering all key requirements including fault tolerance, low latency, throughput scale, and idempotency with no significant gaps.

  • Idempotency in click tracking means the same click event can be safely processed more than once without inflating counts. This is typically handled by assigning a unique event ID to each click and deduplicating on the server side or in the data pipeline before writing to storage.

  • For analytics systems, data freshness is a key non-functional requirement. Near real-time means data is available for queries within seconds to a few minutes of the event occurring, which usually requires a streaming pipeline like Kafka plus a stream processor like Flink or Spark Streaming rather than a batch ETL approach.

Core Entities

You correctly identified the two core entities for an ad click tracking system on your first attempt, showing strong foundational thinking for this type of design.

  • For an ad click tracking system, the two most important entities are Ad and Click. Ad stores the metadata about the advertisement itself, while Click captures each individual interaction event tied to an ad, including data like timestamp, user, and ad reference.

System Interface

You demonstrated a solid understanding of the core inputs and outputs for an ad click aggregation system, correctly identifying the key data flows and granularity requirements from the start.

  • For ad click aggregation systems, the standard output granularity is 1-minute intervals. This matters because advertisers need near-real-time feedback on campaign performance, and 1-minute buckets balance freshness with storage and compute costs.

Data Flow

You demonstrated a strong understanding of the end-to-end data flow for an ad click tracking system, correctly identifying key components like Kafka for streaming and an OLAP database for aggregated queries.

  • Kafka is a great fit for click tracking pipelines because it acts as a durable, high-throughput buffer between the click event and downstream processing. This decouples the write-heavy click ingestion from slower aggregation jobs, preventing data loss during traffic spikes.

  • OLAP databases like ClickHouse, Apache Druid, or BigQuery are optimized for read-heavy analytical queries over large datasets. They store data in a columnar format, making aggregations like ‘total clicks per ad per day’ extremely fast compared to a traditional row-based SQL database.

  • A typical ad metrics data flow has three stages: (1) user clicks an ad and the event is logged, (2) the event is streamed through a pipeline like Kafka into an aggregation layer, and (3) aggregated results are stored in an OLAP store that advertisers query via a dashboard. Knowing this pattern by heart helps anchor your design quickly in an interview.

High Level Design

You demonstrated solid pipeline thinking from the start and quickly fixed the key gap around redirect handling in your second attempt, showing good responsiveness to feedback.

  • In ad click tracking systems, the click service must do two things at once: record the click event AND return an HTTP 302 redirect to the advertiser landing page. A 302 is used because it is a temporary redirect, meaning the browser follows it immediately while the server logs the event. Without the redirect, the user never reaches the advertiser site and the user journey is broken.

  • The click service needs access to the destination URL to perform the redirect. It can get this either by receiving the URL directly in the click request (embedded in the ad link) or by looking it up from the ads database using the adId. Make this lookup path explicit in your diagram so the redirect story is complete.

  • When describing a click event in a system design interview, name the minimum fields that make aggregation and attribution work. A basic click record should include adId, userId (if available), timestamp, and destination URL or a reference to look it up. You do not need a full schema, but naming these fields shows you understand what downstream aggregation and reporting actually need.

Deep Dives

You demonstrated strong instincts throughout this section and improved quickly when given feedback, with your main gaps being around making implicit design decisions explicit and handling edge cases like hot partitions, late events, and atomic cache operations.

  • When a hot key causes one Kinesis shard to exceed its throughput limit (1MB/s or 1000 records/s per shard), use a random suffix fanout pattern like adId_0, adId_1, adId_N to spread writes across multiple shards. The number of suffixes should match the hot ad’s click rate divided by the per-shard limit. Flink then strips the suffix during aggregation so the final count in the database stays clean under the canonical adId.

  • A Redis deduplication check should be done as a single atomic operation, not as a separate read then write. If you check for a key and then set it in two steps, two concurrent requests from the same user can both pass the check before either one writes the key. Use a Redis SET with NX (set if not exists) and EX (expiry) flags in one command to make this safe.

  • For near real time reporting with a freshness target like under 5 seconds, you need to reason about the full end to end latency budget across ingestion, stream processing, and database visibility, not just one component. Flink writing aggregates every second only helps if Kinesis ingestion lag and OLAP write visibility are also accounted for in that same budget.

  • A streaming path alone is not enough for accurate historical analytics because late-arriving events can corrupt already-written aggregate buckets. Store raw click events in durable object storage like S3 and run a periodic batch reconciliation job that compares event timestamps to ingestion timestamps to identify and recompute only the affected time buckets rather than reprocessing the entire dataset.