Eight Teams, Eight Latencies

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

The streaming bill tripled after every player event moved onto real-time jobs, and the platform lead points out that most of the eight teams reading them only look at next-day numbers. Design the pipeline for about 3 billion events a day from 200 million players: matchmaking, trophy unlocks, in-game purchases and session telemetry.

Millions of gamers. The architecture decision changes everything.

Business requirements

Worked solution and explanation

What this problem really is

This is a cost-allocation problem dressed up as a gaming pipeline. Eight teams read the same event firehose, but only a few change the outcome when their data is seconds old, and anti-cheat is the one that cannot wait: a cheater flagged after the match ends has already ruined it. Everyone draws the Kafka topic. What separates candidates is refusing to put every consumer on the same tier. Stream everything and finance and analytics pay streaming prices for numbers they read tomorrow. Batch everything and anti-cheat never bans anyone mid-match.

Building it

Step 1: Land every event once on a durable log

All player events go to one Kafka topic. Its retention is what lets both tiers read the same facts, and what lets a failed batch load replay instead of losing data.

Step 2: Give anti-cheat its own real-time path

anti_cheat_stream is a stateful Flink job over sliding windows of each player's actions, set to 'real-time'. It hands enforcement_service a flagged player ID and a reason, so the ban lands within seconds, well inside an 8 to 12 minute match.

Step 3: Put everything next-day on one batch path

batch_dedup_load is a nightly Spark job that loads the day's events into event_warehouse. Finance reconciliation and the analytics dashboard both read there, so the five teams that only need next-day numbers share one cheap path.

Step 4: Deduplicate purchases on their unique ID

Client retries and processor callbacks redeliver purchases, so the load keeps one row per purchase ID before writing the warehouse. Finance then matches those totals against the processor's daily settlement file to the cent; a duplicate inflates revenue and a drop under-reports it.

The reference design

One durable topic, two tiers: `anti_cheat_stream` acts in real time, while `batch_dedup_load` feeds the next-day readers from `event_warehouse`.
  • raw_game_events (source, Kafka)
  • anti_cheat_stream (transform, Flink); freshness: real-time
  • enforcement_service (consumer, API)
  • batch_dedup_load (transform, Spark)
  • event_warehouse (storage, warehouse)
  • finance_reconciliation (consumer)
  • analytics_dashboard (consumer)
  • raw_game_events -> anti_cheat_stream
  • anti_cheat_stream -> enforcement_service
  • raw_game_events -> batch_dedup_load
  • batch_dedup_load -> event_warehouse
  • event_warehouse -> finance_reconciliation
  • event_warehouse -> analytics_dashboard
Stream everything
Every consumer gets seconds-old data, and the bill pays for it eight times over. Finance still reconciles once a day against a settlement file, so the freshness buys nothing.
Two tiers
Only anti-cheat runs continuously. Next-day consumers share one nightly load, and purchases are deduplicated once, on the path finance actually reads.

Common follow-up questions