Uber logo

How Uber scaled its backend

A dispatch problem that's really a real-time geospatial problem

Matching riders to drivers isn't a normal CRUD problem - it needs to answer 'which drivers are near this rider, right now' continuously, across a constantly moving dataset, at low latency, across many cities simultaneously.

Uber operates across a large number of cities worldwide, each with its own local supply of drivers and demand pattern, and the core dispatch problem has to run continuously in real time - a driver's location a minute ago is stale data for a matching decision made right now.

Interactive

Uber’s stack, mapped

Grouped by where each piece sits in the request path. Click through to see what each one is actually for.

Infrastructure

Services & language

Data & messaging

Backend language

·

Go

Uber has publicly discussed using Go for many backend services where performance and simple concurrency (handling many requests at once) matter - Go was designed at Google partly to make writing highly concurrent network services more straightforward than in older languages.

Click a piece of Uber’s stack to see what it’s for

The same stack, in plain language

Go

Backend language

Uber has publicly discussed using Go for many backend services where performance and simple concurrency (handling many requests at once) matter - Go was designed at Google partly to make writing highly concurrent network services more straightforward than in older languages.

Java

Backend language

Alongside Go, a substantial portion of Uber's original and ongoing backend services are written in Java, particularly older core services that predate the wider move to Go.

H3

Geospatial indexing library

An open-source library Uber built to divide the globe into a grid of hexagonal cells, so questions like 'which drivers are near this point' can be answered by a fast lookup instead of comparing raw latitude/longitude against every driver individually.

Schemaless (on MySQL)

Datastore

A datastore Uber built on top of MySQL to get more horizontal scalability while keeping some of MySQL's operational maturity - rather than switching wholesale to a different database engine, they built a scaling layer on top of one they already trusted.

Kafka

Event streaming

Used extensively at Uber to move high-volume real-time data - trip events, location updates - between services asynchronously, which is essential when thousands of location updates are arriving every second across a city.

Cassandra

Database

Used for some of Uber's data that needs to be available and fast to write across multiple regions, similar to its role at other large-scale companies - trading strict consistency for availability under heavy write load.

Mesos / later Kubernetes

Container orchestration

Systems for scheduling and running Uber's large number of backend service instances across a fleet of machines, deciding which physical or virtual machine each service instance actually runs on.

How it actually works

H3, a hexagonal geospatial index

Uber open-sourced H3, a system for dividing the globe into a hierarchical grid of hexagonal cells, used to index driver and rider locations efficiently. Hexagons have more uniform adjacency than a square grid - every neighboring hexagon is the same distance away, which isn't true of squares (diagonal neighbors are farther than side neighbors) - which made proximity queries like 'what's near this point' cheaper and more consistent at the scale Uber operates at. In practice, this means a driver's location gets mapped to a hexagon ID, and finding nearby drivers becomes a fast lookup of nearby hexagon IDs instead of an expensive distance calculation against every driver in the city.

Moving off a single relational datastore

Uber's early architecture leaned heavily on a single large MySQL setup as the system grew past what that could comfortably handle. Uber's engineering blog documented building Schemaless, a datastore layered on top of MySQL to get horizontal scalability while keeping some of the operational familiarity of a relational engine underneath - instead of throwing away MySQL entirely, they used it as a lower-level storage engine underneath a new distributed layer they controlled themselves.

A services architecture built around independent scaling

Like most companies operating at this scale, Uber split its original monolith into many independently deployable services, specifically so that dispatch, pricing (including surge pricing calculations), mapping, and payments could each scale according to their own very different load patterns instead of being forced to scale together. Dispatch traffic spikes at rush hour in a specific city; payment processing load looks completely different - treating them as separate services means each can be given exactly the resources its own pattern needs.

What “microservices” means here, concretely

Uber runs a large number of backend microservices, historically written in a mix of Java and Go, coordinated through internal service infrastructure and scheduled across their compute fleet with tools like Mesos and later Kubernetes - dispatch, pricing, mapping, and payments are examples of functionally distinct services rather than one shared codebase.

Takeaway

Uber's public engineering content keeps returning to one idea: generic tools work until your core problem (real-time geospatial matching, at global scale) is unusual enough that you have to build a purpose-built layer instead of forcing a general-purpose database to do it.

Based on

  • Uber Engineering Blog - H3: Uber's Hexagonal Hierarchical Spatial Index
  • Uber Engineering Blog - Schemaless, a scalable datastore
  • Uber Engineering Blog - the migration from a monolith to microservices