The Speed Layer

A medium Pipeline Design interview practice problem on DataDriven. Design the pipeline on the canvas: sources, transforms, storage and checks, then get feedback on it.

Domain
Pipeline Design
Difficulty
medium
Seniority
L5

Problem

Activity events arrive from web and mobile clients, about 60 million a day from roughly 8 million users, and hourly, daily and weekly active users are currently counted from them at query time, which is too slow. Design a pipeline that pre-computes all three, refreshed every hour, and serves them.

Dashboards can't wait for raw logs. Something has to happen upstream.

Business requirements

Worked solution and explanation

What this really is

This is a freshness problem and a correctness problem wearing the same metric name. HAU has to land minutes after the hour, DAU goes to investors and must be exact, and mobile clients deliver yesterday's events today. Anyone can draw a stream processor feeding a warehouse. The trap is reaching for HyperLogLog to hit the speed budget, which breaks the investor-exact constraint, or leaning on one nightly recompute, which misses the hourly window and still leaves history wrong.

The default reach is one streaming job keeping approximate sketches, plus a nightly recompute to patch DAU. The sketch number and the recount never agree, so finance cannot file either one. Late mobile events arrive after the daily run, so they are dropped or credited to the wrong day. HAU ends up fresh, DAU is exact only once a night, and history never gets corrected.


Walk the requirements

Step 1: Emit exact counts at every window close

A stream processor holds the unique users per (period_type, period_id) for the hour, the day and the week. When an hour closes, it writes that hour's count to the warehouse; the day closes at midnight UTC the same way. Dashboards read pre-aggregated rows, so nothing is recomputed at query time. Counting raw events at read time is exactly what made product wait until 2am.

Step 2: Hold real user sets, not sketches

Investor DAU cannot be an estimate. The stream processor keeps the real user ids for each open period rather than a probabilistic sketch. Memory scales with the active users in the open windows, which is bounded. A sketch hits the speed budget, but it produces a number that never matches a full recount, and that recount is the figure finance is held to.

Step 3: Give late events a path back into history

Every event carries its event time. The stream processor closes each window on time so HAU stays fresh, while the raw events also land in object storage. A scheduled Spark job recounts any past day or week that a late event touched and overwrites that period's partition, so the corrected figure replaces the original. Dropping events past a lateness cutoff is the version where history goes silently wrong.


The shape that fits

A real-time distinct aggregator writes exact counts per hour, day and week to the warehouse. Raw events also land in object storage, where an hourly recount restates any past period a late event touched.
  • user_events (source, Kafka)
  • event_archive (storage, object storage)
  • distinct_aggregator (transform, Flink); freshness: real-time
  • late_event_recount (transform, Spark); freshness: < 1h; backfill: partition_overwrite
  • pre_aggregated_metrics (storage, warehouse)
  • product_dashboard (consumer, Grafana)
  • investor_reporting (consumer)
  • user_events -> distinct_aggregator
  • user_events -> event_archive
  • distinct_aggregator -> pre_aggregated_metrics
  • event_archive -> late_event_recount
  • late_event_recount -> pre_aggregated_metrics
  • pre_aggregated_metrics -> product_dashboard
  • pre_aggregated_metrics -> investor_reporting

Common follow-up questions