Seconds to Trend
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
- mid
- Asked in
- TikTok
Problem
We run a short-video platform where roughly 5 billion engagement events a day (views, likes, watch-time pings) come off the apps. The trending team needs the hottest videos surfaced within seconds of a spike, while the growth team reports daily active users and 7-day retention on a T+1 cadence from the same events. Design the pipeline that serves both consumers without paying to stream everything.
Business requirements
- When a video starts spiking, the trending team wants it on the surface within seconds, not on tomorrow's report.
- Growth reports daily active users and 7-day retention once a day and needs the counts to be exact.
- Finance flagged that streaming the full firehose for every consumer is expensive; only the consumers that need seconds should pay for it.
Worked solution and explanation
Why this problem exists in real interviews
This looks like a Kafka-and-Spark trivia question but it is really a two-speed problem hiding behind one event stream. Trending wants engagement velocity within seconds; growth wants exact DAU and retention once a day. The trap is picking a single answer for both: stream everything and you pay firehose compute to serve a daily report, or batch everything and trending is always one day stale. The skill being probed is whether you split consumers by their actual latency budget and justify the split out loud.
The default whiteboard reach is one streaming job that writes a metrics table everything reads. It feels modern, but DAU computed on a streaming aggregate is approximate (late mobile events drift the count), reporting publishes a number that wobbles, and finance gets a bill for streaming 5 billion events a day to feed a once-a-day dashboard. Meanwhile trending shares cluster headroom with the heavy daily aggregation and lags exactly when a video spikes.
Walk the requirements
Step 1: Buffer the firehose in one log both paths read
5 billion events a day with 4x peak bursts means producers cannot push straight into consumers. Kafka partitioned by video_id absorbs the spike and gives both the stream tier and the batch tier the same replayable source. Without this buffer, a trending slowdown backpressures the apps and a batch backfill has nowhere to re-read from.
Step 2: Put only trending on the streaming path
Trending is engagement velocity over a rolling 5-minute window, needed within seconds. A stream processor (Flink or Spark Structured Streaming) keys by video_id, maintains the windowed count, and writes the hot list to a serving store the trending surface queries directly. At-least-once is acceptable here because one duplicate barely moves a velocity ranking, so you avoid the cost of exactly-once on the fast path.
Step 3: Put DAU and retention on the batch path
DAU and 7-day retention are T+1 and feed external reporting, so they must be exact and stable once published. A daily Spark job reads the day-partitioned log, dedups on (user_id, date), and lands aggregates in the warehouse. Reusing the streaming approximate counts here would publish a number that drifts as late events arrive. This is the consumer that should NOT be streamed.
Step 4: Decide what each path does with late mobile events
Clients buffer offline and replay events minutes late. The stream tier uses event-time watermarks and accepts that a late event may miss its trending window, which is fine for an approximate velocity metric. The batch tier sidesteps it entirely: it runs after the day closes over the date partition, so a late event that lands before the run is still counted exactly. Same data, two correctness budgets.
The shape that fits
- engagement_events (source, Kafka, 5B/day, partitioned by video_id)
- trending_stream (transform, Flink, 5-min rolling velocity); freshness: < 1min
- trending_store (storage, Redis); freshness: < 1min
- trending_surface (consumer, Trending API); freshness: < 1min
- daily_aggregation (transform, Spark, date-partitioned, dedup on user/date); freshness: < 24h
- analytics_warehouse (storage, BigQuery); freshness: < 24h
- growth_reporting (consumer, Looker); freshness: < 24h
- engagement_events -> trending_stream
- trending_stream -> trending_store
- trending_store -> trending_surface
- engagement_events -> daily_aggregation
- daily_aggregation -> analytics_warehouse
- analytics_warehouse -> growth_reporting
- Ingestion: engagement_events
- Streaming path: trending_stream, trending_store, trending_surface
- Batch path: daily_aggregation, analytics_warehouse, growth_reporting
Common follow-up questions
- A creator complains their video trended for a second and vanished. How would you stabilize the trending signal without making it stale? (Tests window and smoothing choices: longer or overlapping windows, decay, and minimum-volume thresholds, while keeping freshness under a minute.)
- Volume jumps 5x for a global event in 48 hours. What in this design absorbs it and what breaks first? (Tests capacity thinking: Kafka partition count and consumer parallelism scale, but windowed stream state and serving-store write throughput are the first pressure points.)