Courses / System Design Interview / Chapter 25
Module 3 · Design Real Products · Chapter 25 of 39
Design Maps and Navigation
Builds on Back-of-the-Envelope Estimates, Databases: Replication, Partitioning and Choosing a Store, Content Delivery Networks, Distributed Caches, Message Queues and Blob Stores. Next up: Design Nearby Places Search.
Part 1 · Requirements and Scale
The brief
It is the Saturday of Mysuru Dasara. By four in the afternoon, tens of thousands of cars are leaving Bengaluru for the palace lights, about 150 km away, and nearly every driver has asked one maps app for the fastest way. Then a lorry breaks down on the highway near Mandya. Within a minute, the phones crawling past it have reported the slowdown. Within two, the arrival times of the cars behind it have jumped by twenty minutes, and new requests are routed around the jam. Behind that moment sit three systems: a map that draws at once, routes that come back in milliseconds, and arrival times that learn from every phone on the road.
The product: a maps and navigation app for a large country. People pan and zoom the map, search for a place, ask for the fastest route by car or two-wheeler, and follow turn-by-turn directions. The arrival time must stay honest as traffic changes, even at the evening peak. One trip runs through the whole chapter: from Indiranagar in Bengaluru to Mysuru Palace.
This is one of the more algorithmic chapters: its core deep dive is a graph search problem, not only boxes and arrows. On a first pass, take away the idea of shortcuts between region borders and skim the details. Come back to them before you design anything that routes vehicles, such as food delivery or ride-sharing.
What we are building
That Dasara evening hides three systems with very different shapes. Showing the map means serving small square pieces of the map, called tiles, to millions of screens. Finding a route is a graph search that must finish in well under a second. Live traffic is a stream of millions of location updates, turned into road speeds every minute. Treat them as three systems that share one map of roads.
Here is what is in scope today, and what is not:
| In scope | Out of scope today | |
|---|---|---|
| Map | Pan and zoom a map of roads and places; traffic colours on roads | Street-level photos, 3D buildings, place search in depth |
| Routes | Car and two-wheeler routes with an ETA and a few alternatives | Public transport timetables, multi-stop trips |
| Navigation | Turn-by-turn guidance; rerouting when you leave the route or traffic changes | Lane-level guidance |
| Data | Live traffic from phones that share their location | Collecting the map itself: surveys and imagery |
The road data itself arrives as a regular map release; the work here is to serve it fast and keep it live. The non-functional requirements, as numbers:
- Smooth map: tiles appear within about 100 ms while panning, so they must come from a cache close to the user.
- Fast routes: a route between any two points in the country comes back in under a second, even at the evening peak.
- Honest ETAs: within about 10% on most trips, so within about 17 minutes on the three-hour Mysuru drive, using traffic no more than a couple of minutes old.
- Works on the move: guidance continues through tunnels and weak signal; the app does not need the server for every turn.
- Private: pings feed only road speeds. Each trip gets a random id, the first and last few hundred metres (near homes) are dropped, and only aggregates are kept long term.
How big it gets
Before choosing any machinery, size the flows. Start with the number that shapes the traffic pipeline: location pings from people who are navigating. Assume a large country at the evening peak with 5 million drivers navigating at once (the Dasara crowd is a local spike inside that), each phone recording a position of about 100 bytes every 4 seconds.
Try it first: how many pings a second arrive at the peak, how much data is that, and how much arrives in a day?
- 5 M ÷ 4 s = 1.25 M pings a second; at about 100 bytes each, about 125 MB/s.
- Nights are quiet, so the daily average is about a third of the peak: about 42 MB/s.
- 42 MB/s × 86,400 s ≈ 3.6 TB of raw pings a day.
The other quantities follow the same way:
| Quantity | Estimate | What it means |
|---|---|---|
| Location pings at peak | ≈ 1.25 M /s, about 125 MB/s | A partitioned stream, not a database |
| Raw pings per day | ≈ 3.6 TB | Turned into road speeds within minutes; raw pings kept only a few days |
| Road graph for a large country | ≈ 30 M junctions and ≈ 75 M one-way edges (assumed) | A few GB for the graph and shortcuts, tens of GB with road shapes: fits in one server's memory |
| Route requests at peak | ≈ 20,000 /s: new trips (5 M drivers on 30-minute trips ≈ 3,000 /s) plus a re-check every 5 minutes (≈ 17,000 /s) | Each query must be cheap; see the routing deep dive |
| Map tiles at street zoom | ≈ 69 billion worldwide at zoom 18 | Far too many to pre-render; most are ocean or empty land |
1.25 million writes a second is far beyond one database, but easy for a partitioned stream: 100 partitions take 12,500 pings, about 1.25 MB, a second each. Phones batch about four fixes per request, so the servers see roughly 310,000 requests a second while the stream still carries every position. None of it is kept for long: within a minute or two, the pings become one speed per road segment.
Part 2 · API, Data and the Big Picture
The API
With the flows sized, the app talks to three services, each with its own call pattern. Here is the Mysuru trip as calls:
GET /v1/tiles/{z}/{x}/{y}.mvt?v=2026-10-01 -> 200 vector tile (cached for days)
GET /v1/places/search?q=mysuru+palace&near=12.97,77.64 -> 200 { places[] }
POST /v1/routes { from: [12.97, 77.64], to: [12.31, 76.66], mode: "car", departAt }
-> 200 { routes: [{ polyline, etaSec, steps[] }] }
POST /v1/trips/{tripId}/pings { points: [{ lat, lng, speed, heading, t }] } -> 202
GET /v1/traffic/{z}/{x}/{y} -> 200 { segments: [{ id, speedKmph }] }
POST /v1/trips/{tripId}/reroute { position, heading } -> 200 { route } or 204 (no better route)Tile URLs carry the map version, so a new map release gets new URLs instead of stale cached tiles.
Tiles are addressed by zoom level and position (z/x/y), which makes them ideal for caching: the same URL means the same bytes for every user until the map version changes. Traffic is a separate, small overlay refreshed every minute, so the large base tiles can stay cached for days.
Pings are batched: the phone collects a few positions and sends them in one request, which saves battery and radio time. The server answers 202 at once; nothing the driver sees waits for the traffic pipeline. departAt lets the family plan tomorrow's drive with the typical traffic for that hour.
A route includes its full shape, every turn and an ETA for each step. The phone can guide the driver all the way to Mysuru without asking the server again, unless traffic or the driver's choices change something.
The data model
Behind those calls sits the core data: the road graph. Junctions are nodes and road segments are directed edges, so a two-way road is two edges. Each edge carries what routing needs to price it.
id (pk)latlngregion_idid (pk)from_junctionto_junctionlength_mroad_classspeed_limitgeometryfrom_segment + to_segment (pk)rule: no turn, no U-turnsegment_id (pk)speed_kmphsamplesupdated_atsegment_id + week_slot (pk)typical_kmph- segments from_junction → junctions
- segments to_junction → junctions
- turn_rules from_segment → segments
- live_speed segment_id → segments
- speed_profile segment_id → segments
speed_profile holds the typical speed of each segment for every 15-minute slot of the week (7 × 96 = 672 slots), learned from months of history. It answers "how fast is this road on a Monday at 9 am" when live data is missing, and it predicts traffic for the part of a long trip that is hours away.
Each kind of data lives where its access pattern fits:
| Data | Where it lives | Size and change rate |
|---|---|---|
| Road graph and shortcuts | In memory on every routing server | A few GB, tens with road shapes; split with each map release, shortcut values refreshed every minute |
| Segment index | In memory on routing and map-matching servers | About 2 GB; rebuilt with each map release |
| Map tiles | Blob store behind a CDN | Hundreds of GB (vector) to many TB (raster); versioned by map release |
| Live speeds | In-memory store, partitioned by region | One row per segment; updated every minute |
| Speed profiles | Key-value store, loaded into routing servers | 672 slots × 75 M edges ≈ 50 GB raw; similar roads share a curve, so servers keep a curve id per edge |
| Raw pings | Partitioned stream, deleted after a few days | Terabytes a day; kept only long enough to aggregate and check quality |
Only live speeds, and the shortcut values computed from them, change by the minute; everything else is rebuilt offline and copied.
The big picture
Put together, the pieces form three lanes. The app pulls tiles from the CDN, sends pings into a stream that aggregators turn into live speeds, and asks the routing service, which loads those speeds into memory, for routes. The scene follows the Dasara evening: the map opens, the Mysuru route comes back, and then a jam changes it.
Watch for the one link between the lanes: pings become speeds that routing loads
Read it as steps
Dasara evening in one picture: map tiles, live traffic and the Mysuru route, which changes when the highway jams.
The three lanes share almost nothing at request time. Tiles never touch the routing service, and pings never wait for a route. The only link is the live speed table: aggregators write it every minute and routing servers load it, so a route query never waits on another service.
Tiles need bandwidth, routes need CPU and pings need write throughput. Keeping the lanes apart lets each scale on its own, and a failure in one, such as a stalled ping stream, leaves the other two working.
Part 3 · Deep Dives
Why plain search is too slow
Routing is the hardest part of this design: a country-wide route in milliseconds is the one problem that adding servers cannot fix at a sane cost.
The big picture showed the Mysuru route coming back in about 10 ms. This page asks why that is hard. Routing is a shortest-path search on the road graph, where each edge's weight is its travel time (length divided by speed), not its length.
The textbook tool is Dijkstra's algorithm, and it behaves like a ripple from a stone dropped in a pond. It settles junctions in order of travel time from the start, always taking the nearest one not yet settled, until the destination is settled. A ripple spreads in every direction at once.
That is the problem. Mysuru Palace is about 150 km and close to three hours from Indiranagar, so the search first settles every junction it can reach sooner: all of Bengaluru, and out past Tumakuru, Kolar and Hosur, which lie in the wrong direction. That is in the order of a million junctions, or about a second of CPU. Treat that second, and the 10 ms later in this chapter, as illustrative: real figures depend on the code and the graph, but a gap of about a hundred times is the point.
Most requests are shorter trips inside one city, but suppose every query cost a second: 20,000 queries a second would need about 20,000 CPU cores, and every driver would wait a second for each reroute. The usual trims help only a little:
| Approach | What it explores | Rough cost of a long query |
|---|---|---|
| Dijkstra | A ripple around the start until it reaches the destination | About a million junctions; about a second |
| A* | A shape stretched towards the destination, guided by straight-line distance | Fewer junctions, but the guess must assume top speed in a straight line, so the gain is modest |
| Search from both ends | Two smaller ripples that meet in the middle | Roughly half the work |
The trims make the ripple smaller, not different. The big win comes from doing work in advance, once, so that a query can skip most of the map. Which work would let a query skip the lanes of Mandya?
Shortcuts across region borders
Think about how you would plan the Mysuru drive yourself. You care about the lanes near home and the lanes near the palace; in between, you simply take the highway. Nobody plans a way through the lanes of Mandya.
Routing can work the same way. Split the graph into regions of a few thousand junctions each: a neighbourhood like Indiranagar inside the city, hundreds of square kilometres of farmland outside it. A region's border junctions are where its roads cross into neighbouring regions. For every region, precompute the best travel time between each pair of its border junctions. Each value is a shortcut: one edge that stands for a whole path through the region.
A query then searches the start's region in full detail out to its border junctions, crosses the middle on shortcuts, and searches the destination's region in from its borders.
Nothing is lost. Any route through a region enters and leaves it at border junctions, and the shortcut already holds the best time between them, so the search finds the exact fastest route, over a much smaller graph. Each shortcut also remembers the path it stands for, so the final route can be unpacked into real roads.
In numbers, for illustration: 30 million junctions in regions of about 3,000 make 10,000 regions. With about 30 border junctions each, a region has about 870 shortcuts (30 × 29, one per ordered pair), so the country needs about 9 million shortcut values, some 35 MB at 4 bytes each. The middle of a trip becomes a graph of about 150,000 border junctions, since neighbours share them, instead of 30 million junctions.
Is one level enough for a 150 km trip? The next page shows why not, and what to do about it.
Stacking the levels
One level is not enough. Indiranagar to Mysuru crosses several hundred small regions, so the search still settles thousands of border junctions, each with about 30 shortcuts to scan: roughly ten times less work than plain search, not the hundred times the design needs.
So stack the levels. Group about 30 neighbouring regions into a level-2 region, roughly a district, with shortcuts between its borders, computed cheaply from the level-1 shortcuts inside it. Group those again into level 3, roughly a state: 10,000 small regions become about 330, then about 11.
The search follows one rule: at every junction, use the shortcuts of the biggest region that contains neither the start nor the destination. That means every lane near Indiranagar, small-region hops a few kilometres out, district-sized hops across the middle, and down again near Mysuru: lanes to a state highway, then a national highway.
Predict before you watch: plain search and the shortcut search both look for the Indiranagar to Mysuru route. Which parts of the map does each read road by road?
- Plain search reads every road it can reach in under three hours, including Tumakuru, Kolar and Hosur.
- The shortcut search reads every road only in the two end regions and crosses the rest on precomputed hops.
Watch for where the work goes on one 150 km trip, Indiranagar to Mysuru Palace
Read it as steps
Plain search reads every road in reach; the shortcut search reads roads only near the two ends.
The search did not get cleverer; the graph it searches got smaller. In this illustration a few thousand junctions replace a million, about 1 s becomes about 10 ms, and 20,000 queries a second need around 200 cores instead of 20,000: a handful of large servers per region, each holding the graph and every level in memory. For Bengaluru to Delhi, about 2,100 km, plain search would settle much of the country, while the shortcut query adds only a level or two.
Keeping shortcuts fresh
Shortcut values are travel times, and travel times change. When the lorry blocks the highway near Mandya, every shortcut whose best path runs along that stretch is suddenly wrong. How do shortcuts keep up with live traffic?
The design keeps a slow step and a fast step apart. Splitting the graph depends only on the road layout; shortcut values depend on speeds. The split is hours of offline work, redone with each map release. The values are recomputed every minute from the latest live speeds.
The refresh is cheap because it is local. A small region's values come from about 30 short searches inside its 3,000 junctions, tens of milliseconds of work, and a bigger region reuses the shortcuts of the smaller ones inside it. The Mandya jam touches one small region and the two bigger regions around it, so updating them takes well under a second. At the evening peak, when speeds change everywhere, recomputing all 10,000 small regions costs a few hundred core-seconds: about ten seconds on one 64-core server.
A refresh service publishes the new values, about 35 MB for the small regions, and each routing server swaps them in all at once, so no query mixes old values with new ones. A closed road is the same move with an infinite weight: the next refresh routes everyone around it.
Some route planners instead rank every junction by importance and add shortcuts that skip the less important ones, so each search climbs only towards bigger roads from both ends. Queries are faster still, but those shortcuts are tied to one set of weights, so a refresh every minute is much harder. That family suits weights that rarely change, such as offline maps on a phone; region shortcuts suit live traffic.
Snapping a point to a road
Every query starts with a smaller search of its own. The family's phone reports a GPS fix outside their gate in Indiranagar, and they tapped Mysuru Palace as the destination. Both are points, but the graph needs a road segment and a position along it. Checking all of the country's roughly 45 million road segments (a two-way road counts once here) would take longer than the route itself, so the segments get a spatial index.
Cut the map into a grid of cells about 150 m across, and list in each cell every segment whose shape passes through it; a long highway segment appears in many cells. To snap a point, read its cell and the eight around it, measure the distance to each candidate segment, and project the point onto the closest. If the nine cells hold no road at all, as in a field outside a village, widen the search ring by ring.
The next chapter, on nearby places, builds the same kind of grid for places and shows why the eight neighbours matter. The other common choice is an R-tree, offered by databases with spatial support, which groups segments into nested bounding boxes. Nearest by distance is only the start; four rules keep a snap off the wrong road:
| Rule | Why |
|---|---|
| Match the phone's heading | Two parallel roads, or a flyover above a service road, can be equally close by distance alone |
| Skip roads the mode cannot use | The segment nearest a doorstep is often a footpath |
| Snap a destination to its side of the road | On a divided road, the wrong side can add a long U-turn |
| Use the last few fixes, not one | One fix can be 30 m off between tall buildings |
Size: about 45 million segments, each listed in two or three cells at 16 bytes an entry, is about 2 GB, so every routing server keeps the index in memory beside the graph. The traffic pipeline, on the next page, uses the same index to snap whole traces of fixes instead of one point.
Live traffic and ETAs
Snapping placed one point on a road. The traffic pipeline does the same for millions of points and answers a harder question: how fast is each road moving right now? Every navigating phone is a traffic sensor.
- 1Ingestpings land in a stream partitioned by region, so one area's data stays together
- 2Match to roadsGPS is off by about 5 m in open sky and tens of metres between tall buildings; map matching snaps each trace to the roads it most likely followed
- 3Measurethe time between two points on a segment gives that car's speed on it
- 4Aggregateevery minute, take the median of recent speeds per segment
- 5Publishwrite live speeds; the shortcut refresh and routing servers pick them up
Use the median, not the average. A bus waiting at its stop, or a GPS jump that implies 300 km/h, is an outlier; on a segment with few samples one outlier can drag an average far off, while the median barely moves. Where data is thin, such as a quiet road at 3 am, fall back to the typical speed for that time of week.
An ETA is the sum of travel times along the route. Here is the Mysuru trip on the evening of the breakdown:
| Stretch | Length | Speed now | Time |
|---|---|---|---|
| Indiranagar to the highway | 15 km | 20 km/h | 45 min |
| Highway to Mandya | 80 km | 80 km/h | 60 min |
| Past the broken-down lorry | 2 km | 6 km/h | 20 min |
| Mandya to Mysuru | 45 km | 90 km/h | 30 min |
| Mysuru streets to the palace | 8 km | 24 km/h | 20 min |
| Whole route | 150 km | 175 min |
Length15 km
Speed now20 km/h
Time45 min
Length80 km
Speed now80 km/h
Time60 min
Length2 km
Speed now6 km/h
Time20 min
Length45 km
Speed now90 km/h
Time30 min
Length8 km
Speed now24 km/h
Time20 min
Length150 km
Speed now
Time175 min
Look at the lorry's row. A car 5 km behind it reaches the jam in minutes and should be charged the full 20. A family leaving Indiranagar reaches it in about 105 minutes, and by then the lorry may well be gone. So blend: live speeds for the next stretch, shifting to the typical speed for the time you will arrive further out. For the family, that prices the stretch at its typical 1.5 minutes and the trip at about 2 hours 37 minutes. How fast to shift is learned by comparing past ETAs with actual arrivals.
Map tiles and zoom levels
The last lane is the one people see first: when the family opens the app, the map must appear within about 100 ms. The world map is cut into square tiles arranged as a pyramid. At zoom 0 one tile shows the whole world. Each zoom level splits every tile into four, so zoom z has 4^z tiles and each tile is half as wide as one level up. Five levels show how fast it grows:
| Zoom | Tiles in the world | One tile is about | Good for |
|---|---|---|---|
| 0 | 1 | the whole world | the globe |
| 5 | 1,024 | 1,250 km across | a country |
| 10 | ≈ 1 million | 39 km across | a city |
| 15 | ≈ 1.1 billion | 1.2 km across | streets |
| 18 | ≈ 69 billion | 150 m across | buildings |
Tiles in the world1
One tile is aboutthe whole world
Good forthe globe
Tiles in the world1,024
One tile is about1,250 km across
Good fora country
Tiles in the world≈ 1 million
One tile is about39 km across
Good fora city
Tiles in the world≈ 1.1 billion
One tile is about1.2 km across
Good forstreets
Tiles in the world≈ 69 billion
One tile is about150 m across
Good forbuildings
Widths are at the equator and shrink towards the poles. A phone screen shows a dozen or so tiles at a time, so opening the map costs a dozen or so small requests, almost all answered by the CDN.
You cannot pre-render 69 billion tiles, and you do not need to: most are ocean or empty land that nobody zooms into. Pre-build the low zooms everywhere and the high zooms over populated areas, render the rest on first request, and cache them like any other tile.
Tiles come in two kinds. Raster tiles are pre-drawn images: little work for the phone, but larger, a new set for every style and language, and labels that turn when the map rotates. Vector tiles carry road and building shapes plus labels, and the phone draws them: smaller, one set for day, night and every language, labels that stay upright, but drawing needs the phone's GPU. Vector tiles are the usual choice for apps; raster tiles still suit simple web maps and very old phones.
When the map data changes, publish new tiles under a new version in the URL. Old cached tiles simply stop being requested, so there is nothing to purge from thousands of edge caches.
Part 4 · Bottlenecks, Failures and Trade-offs
What breaks
With the three lanes built, here is how each one fails. Every failure below has a planned response, and each row names what the user notices as well as what the system does.
| Problem | Effect | Response |
|---|---|---|
| A festival rush, like Dasara evening | Route requests in one area jump several times | Routing servers are identical copies: add more behind the load balancer, warmed up before known dates |
| Traffic pipeline stalls | Live speeds stop updating | Fall back to typical speeds by time of week; ETAs get less sharp, routes still work |
| Bad pings | A faulty or faked device reports a jam | Medians and minimum sample counts; cap any one device's influence |
| New map release | Graph, shortcuts and tiles all change | Build offline, roll out to routing servers a few at a time; new tile URLs by version |
| A zone or a whole region fails | Routes and live traffic stop for users served there | Every zone runs routing servers that hold the whole graph. DNS moves users to another region, whose aggregators compute speeds for the moved area from new pings, with typical speeds for the first few minutes. Tiles keep coming from the CDN |
| A road closes for a procession | Routes lead drivers into a closed road | Mark the segment closed in the live speeds (an infinite weight); the next refresh routes around it |
Most of these responses work because the expensive data is read-only at request time. The graph and tiles are built offline and copied everywhere, so losing a server loses nothing. Only live speeds, and the shortcut values computed from them, change all the time, and even they have a fallback in typical speeds.
Trade-offs and cost
Each choice in this design buys one thing with another. Four are worth naming:
| Choice | Gain | Cost |
|---|---|---|
| More precomputation | Faster queries | Longer rebuilds; harder to fold in live traffic quickly |
| Pings every 2 s instead of 4 s | Sharper speeds, faster jam detection | Twice the ingest and more battery use |
| Vector tiles | Smaller downloads; restyle without new tiles | Phones must draw them; old phones struggle |
| Guidance on the phone | Works offline; fewer server calls | Traffic reroutes need a separate check |
Most of them trade freshness or speed against work done somewhere else: on the build servers, in the ping stream, or on the phone.
Tile bandwidth dominates the bill: if 50 million people a day each load about 100 tiles of roughly 20 KB, the CDN moves about 100 TB a day, while routing runs on a few dozen large servers across all regions and zones.
Part 5 · Going further
Navigation and rerouting
Optional: what the phone does once the trip starts, and how rerouting avoids flapping and herding.
Once a route is chosen, the phone does most of the work. It holds the route's shape and every turn, and compares each GPS fix with the route locally. No server is needed to say "turn left in 200 m", so guidance keeps working when the network drops. In a tunnel, where GPS drops out too, the phone estimates its position from its last known speed along the route.
There are two reasons to reroute, and they are handled differently:
| You left the route | Traffic changed | |
|---|---|---|
| Detected by | The phone: several fixes in a row more than about 50 m from the route | A re-check every few minutes: the phone sends its position, and the server looks for a faster route |
| Response | Ask for a new route from the current position at once | Offer the new route only if it saves enough time |
| Typical rule | React within a few seconds | Switch only if it saves, say, 5 minutes or 10% |
The threshold for traffic reroutes prevents flapping: without it, two routes with nearly equal ETAs would swap every minute and confuse the driver. A subtler problem is herding: if every car behind the Mandya lorry is sent down the same village road, the village road jams. One remedy is to spread drivers across several good alternatives; another is to add the expected extra traffic to a side road's weight before sending more drivers there.
Download the tiles along the route and keep the route on the phone. A dead zone on the highway then costs only the traffic updates, not the guidance.
Part 6 · Interview kit
The 45-minute answer
A 45-minute slot leaves about 40 minutes of design once introductions and your own questions are done. Here is maps on that clock.
| Minutes | What you say and draw | Key number or decision |
|---|---|---|
| 0–5 | Requirements: pan and zoom, car and two-wheeler routes, turn-by-turn guidance, live ETAs. Out of scope: public transport, collecting the map | Routes in under 1 s; ETAs within about 10%; tiles within about 100 ms |
| 5–8 | Only the estimates that decide something: pings and route requests at the evening peak | 1.25 M pings/s needs a partitioned stream; 20,000 routes/s means each query must take milliseconds |
| 8–13 | API: tiles by z/x/y with a map version, routes, batched pings. Data: junctions and segments, live speeds, typical speeds by time of week | Edges are weighted by travel time, so traffic changes weights, not the graph |
| 13–22 | Three lanes: tiles from a CDN; pings into a stream, aggregators and live speeds; routing servers with the graph in memory | The lanes meet only at the live speed table |
| 22–37 | Core deep dive: why plain search is slow, region shortcuts, stacked levels, refreshing shortcut values. Then live traffic: map matching, medians, the ETA blend | About 1 s per long query falls to about 10 ms (illustrative): 200 cores instead of 20,000 |
| 37–40 | Wrap-up: the pipeline stalls, a zone or region fails, a bad map release; trade-offs; what you would measure | ETA error per city and hour is the health signal |
Pick the deep dive from the interviewer's question. If they ask how a route comes back so fast, go deep on region shortcuts and stacked levels. If they ask where the ETA comes from, cover the ping pipeline, map matching and the live and typical blend. If they care most about the screen, cover the tile pyramid and versioned URLs.
- Say
- "Edges are weighted by travel time, so live traffic changes the weights every minute, while the graph itself changes only with a map release."
- Say
- "I precompute shortcuts between region borders, so a 150 km route takes milliseconds instead of about a second, and stays exact."
- Say
- "1.25 million pings a second go into a partitioned stream and come out as one speed per segment per minute."
- Avoid
- "Run Dijkstra on the whole map for every request." It works for a city, not for a country at peak.
Interview drill
Interviewers change the problem to see whether your design bends or breaks. Try each one before opening the answer.
A festival evening: route requests jump from 20,000 to 200,000 a second for two hours. What do you change?
- Add routing servers, but each loads tens of GB before it serves: keep warm spares and scale up before known dates.
- Most requests are re-checks: under load, stretch them from every 5 to every 10 minutes, and skip routes with no slowed segment.
- Cache popular routes for a minute, keyed by the snapped start and end cells: a crowd leaving one ground asks the same question.
- Shed by priority: new trips first, then drivers who left the route, then traffic re-checks.
Add two-wheeler routing as a full mode, with its own speeds and road rules. What changes in the data?
- Each segment gains per-mode rules: some expressways ban two-wheelers, and some narrow lanes suit only them.
- Two-wheelers filter through jams, so tag each ping with its mode and keep live and typical speeds per mode.
- Each mode needs its own shortcut values, since they depend on the weights; the region split is shared.
The ETA goal tightens: 90% of trips must arrive within 10% of the first ETA, and today only 75% do. What do you add?
- Log each trip's first ETA, its route and the actual arrival: completed trips become training data.
- Train a correction model that predicts the error of the summed segment times from city, hour, road classes, turns and weather.
- Serve it beside routing, a few milliseconds per route; roll it out in shadow first, compare per city and hour, and fall back to the base ETA if it fails.
- Common miss
- Weighting edges by distance. Routes must minimise time, and only time weights let traffic change the answer.
- Common miss
- Storing every ping. Pings become one speed per segment per minute, and raw data is dropped within days, which also protects privacy.
Wrap-up
Next, Design Nearby Places Search turns the cell grid you met in snapping into the whole design: finding every café within 500 m of a user, fast.
Part 7 · Check yourself
Quick check
Q1Two days after a map release, ETAs from Bengaluru to Mysuru run 20% too optimistic, yet every server looks healthy. What do you check?
Think it through, then check.
- Check that typical speeds still match segment ids: renumbered segments lose their history and fall back to speed limits, which are optimistic.
- Check map matching on new or changed roads: wrong snaps credit slow traffic to the wrong road.
- Guard future releases: carry speed history across id changes and compare ETA error before and after.
Q2Product adds an "avoid tolls" switch, and the family driving to Mysuru turns it on. Why does it trouble the shortcut design, and what do you do?
Think it through, then check.
- Shortcut values assume one set of weights; with tolls off, any shortcut whose best path uses a toll road is wrong.
- Store a second value per shortcut, the best time without tolls: the region split is shared, only the values double.
- Rare options, such as avoiding ferries, can run a slower search with a time limit instead.
Q3Refresh shortcut values with live speeds every minute, or keep typical speeds and re-price only the chosen route? What does each cost?
Think it through, then check.
- Every minute: routes avoid today's jams, at the cost of constant refresh work.
- Typical speeds only: cheaper, but blind to today's jam; the ETA can be corrected, but the driver still sits in it.
- A middle path: pick a few candidate routes on typical speeds, then re-price them with live speeds and keep the best.
Q4At the evening peak, the ping stream's consumers fall 20 minutes behind. What do users notice, and what should the system do by itself?
Think it through, then check.
- Live speeds go stale; once older than a limit, say 5 minutes, routing switches to typical speeds for that time of week.
- Routes still come back, but a fresh jam like the Mandya lorry goes unseen.
- To catch up, process the newest pings first and drop the backlog: 20-minute-old pings describe traffic that has gone.
Q5Which building block carries 1.25 million pings a second from phones to the aggregators, and why not a database?
Think it through, then check.
- A partitioned, log-based message queue (the message queue chapter), keyed by region, so each area's pings reach one aggregator in order.
- It absorbs bursts, lets aggregators replay after a crash, and drops old data by retention, not row by row.
- A database would pay for durable, indexed writes of data that is stale within minutes.