Uber architecture visualization
All architectures
Technical deep dive

Uber

How Uber built a real-time data platform to match riders and drivers in 10,000 cities.

Numbers that matter

30M+
Trips / day
10,000+
Cities
trillions
Kafka msgs / day
100k+
Pinot queries / sec
P99 < 1s

The stack

Kafka· streaming
Apache Flink· stream compute
Apache Pinot· real-time OLAP
Apache Hudi· table format
Presto· interactive SQL
Spark· batch compute
HDFS· storage
Cassandra· operational store
Michelangelo· ML platform

The architecture as an interactive dashboard

The idea is simple: learn by reading the diagram. Every box and arrow tells part of the story — click to open.

How to read this diagram
Boxes = components

Color signals the role: client, streaming, storage, compute, ML, serving. Click any box to see what it is, why it's used, and what happens there.

Arrows = data flow
streaming· live eventsbatch· scheduled jobsync· direct callserve· user-facing
Click any step to explore
eventsbatch ETLsurge · signalsassignment
Rider appClientclick →
Driver appClientclick →
KafkaStreamingclick →
FlinkComputeclick →
Apache PinotServingclick →
Apache HudiStorageclick →
Spark ETLComputeclick →
MichelangeloMLclick →
DispatchServingclick →
Uber's platform runs two loops in parallel: a real-time loop (Kafka → Flink/Pinot → ops decisions in seconds) and a batch loop (Hudi → Spark/Presto → ML training that feeds dispatch back to the app).
Optional
Read the full written deep dive
The same ideas as the diagram, with more context — recommended after exploring the steps.

The problem: 30M rides a day, and every one is a real-time decision

Uber isn't a "big data" problem — it's a big real-time problem. When you tap "request", the platform has to:

  • Find nearby drivers (geo query on live driver state)
  • Compute a fare (surge model, based on last-N-minute demand/supply)
  • Route the trip (ETA from live traffic)
  • Score for fraud (in <100ms)
  • Update dozens of downstream systems (accounting, driver earnings, marketplace metrics)

All of this in about a second. And then the same event has to land in a lakehouse for tomorrow's model retraining. That dual requirement — sub-second AND analytical — is what shaped every choice in the platform.

Kafka is the nervous system

Every meaningful event at Uber flows through Kafka. Uber runs one of the largest Kafka deployments in the world — trillions of messages a day across thousands of topics. Two design choices matter:

  • Topics are keyed by entity, not by service. trip_events keyed by trip_uuid means every consumer sees ordered updates per trip.
  • Producers write once; Kafka Connect / uReplicator fans out to regions and downstream sinks. Producers don't know or care where the data ends up.

Uber also open-sourced uReplicator (later replaced by MirrorMaker 2 improvements) specifically to solve cross-datacenter replication at their scale — Kafka's own tooling wasn't enough.

Apache Pinot: sub-second OLAP on live data

Traditional warehouses answer analytical queries in seconds-to-minutes. Uber needed milliseconds — to power surge pricing dashboards, fraud detection, ETA calibration. They co-created Apache Pinot to fill that gap.

Pinot is a columnar OLAP store that ingests directly from Kafka and answers slice-and-dice queries in <100ms at 100k+ QPS. A concrete example:

-- "How many completed trips per city in the last 5 minutes?"
-- Backs the surge pricing model. Runs every few seconds.
SELECT city_id, COUNT(*) AS trips
FROM trip_events
WHERE event_type = 'TRIP_COMPLETED'
  AND event_time >= ago('PT5M')
GROUP BY city_id;

Same SQL you'd write against Postgres. But Pinot pre-materializes the segments, keeps hot data in memory, and returns in 20-50ms. That's the difference between "surge pricing that reacts to reality" and "surge pricing that reacts to what happened 20 minutes ago".

Apache Hudi: the lakehouse before lakehouses were called that

Uber authored Apache Hudi in 2016, three years before "lakehouse" was a marketing term. The problem they solved: how do you do upserts on HDFS/S3? A trip can update dozens of times (accepted → started → completed → adjusted → refunded), and rewriting the whole partition every time was untenable.

Hudi introduced two table types that are now standard vocabulary:

  • Copy-on-Write (CoW): rewrites files on update. Simpler reads, higher write cost. Good for analytics-heavy tables.
  • Merge-on-Read (MoR): writes deltas; readers merge on-the-fly or via a compaction job. Lower write latency, higher read cost. Good for high-velocity tables like trip state.

Every modern lakehouse (Iceberg, Delta) has some version of this now. Hudi shipped it first because Uber needed it.

Michelangelo: ML as a product, not a project

Michelangelo is Uber's internal ML platform. The pitch to internal teams: give us your features and your training data pointer, we handle everything else — training, deployment, monitoring, retraining. Same rails power fraud detection, ETA prediction, driver scoring, matching.

The key architectural idea is the feature store as first-class citizen. Features are defined once (in Hive/Hudi tables) and served both offline (for training) and online (via a low-latency store like Cassandra). This is the same pattern Netflix uses — and every serious ML org converges on it.

What you can actually steal from this design

  • Real-time OLAP is its own tier. If your dashboards need sub-second freshness, don't try to make Snowflake do it. Look at Pinot, Druid, or ClickHouse. They exist for this exact reason.
  • Upserts on the lake are non-negotiable. The moment your data has any correction, adjustment, or slowly-changing dimension, you need a table format with upsert semantics. Hudi, Iceberg, or Delta — pick one, but pick one.
  • Kafka topics are entities, not services. A topic per service creates a graph of point-to-point pipelines. A topic per entity (user, order, session, trip) creates a stable interface every consumer can share.
  • The ML platform IS the ML strategy. If every team builds their own training loop, you have five ML platforms and no learnings. Michelangelo (or something like it) is the multiplier.

Curated sources

The public sources behind this analysis, with our take on why each one is worth your time.

Learn what makes this work

The DataForge courses that cover the pieces of this architecture.

Last updated:
← See all architectures