Design Nearby Friends
Nearby Friends shows a user which of their friends are close by right now. It runs only for users who choose to share their location.
The ask
Nearby Friends answers a live question. Which of my friends are near me now?
Sharing is a choice, and it runs both ways. A user sees a friend only when both share with each other.
The answer is a list with rough distances. It is not a live map of exact movements.
Alerts are the second shape. The service can tell a user when a sharing friend comes near.
The radius is the user's own setting. A walk across town and a night out can use different radii.
Estimate the scale
The service has 1,000,000,000 users. Only 10% share their location.
1,000,000,000 users x 10% = 100,000,000 tracked users.
A tracked user sends a location update every 60 seconds.
100,000,000 updates / 60 seconds = about 1,666,667 updates per second.
One stored location takes 16 bytes. 100,000,000 locations x 16 bytes = 1,600,000,000 bytes of latest locations.
That is about 1.6 GB, small enough to hold in memory. The write rate is the problem, not the storage.
API and data
The update operation carries a user ID and a location. It also carries the time the location was read.
The nearby operation takes a user ID and a radius. It returns the sharing friends inside that radius, with rough distances.
A settings operation turns sharing on or off. It can also pause sharing for a while.
The stored record per user is small. It holds the latest location, its time and the sharing setting.
High-level design
A location service takes the update stream. It writes each latest location into a geospatial index keyed by user.
The friend lists come from the social graph. The social graph stores who is friends with whom.
A nearby query joins the two. It finds tracked users near the point, then keeps only the asker's friends.
An alert worker watches for friends entering the radius. It sends alerts through the notification system.
How a nearby check runs
The asker's phone sends its location with the request. The service reads the cells around that point.
Candidate users come from those cells. The friend check then removes everyone who is not a friend of the asker.
A sharing check runs next. A friend who paused sharing drops out, even on a friend list.
Rough distances go back in the answer. Exact locations never leave the service.
The answer sorts by rough distance. The nearest friends come first, in bands rather than exact order.
Deep dive: the update firehose
About 1,666,667 updates land every second. Most of them change nothing that anyone can see.
A user sitting still sends the same place again and again. The service drops updates that match the stored location.
A moving user crosses a cell edge rarely. Only a cell change can change who is near, so only a cell change triggers friend checks.
Phones batch updates when the app is closed. Stale updates arrive late and lose to the newest stored time.
The index shards by cell. One busy city shard takes more updates than a quiet region, so hot cells split.
Deep dive: privacy and safety
Location is sensitive data. The design treats every location as private by default.
Distances come back rounded, in bands. A friend sees a rough band, never a point on a map.
Sharing can pause at any time, and a block ends sharing at once. A blocked user never learns of the block from this answer.
Old locations are deleted, not kept. The service stores the latest location and forgets the path behind it.
A user who never turned sharing on has no record. There is nothing to leak.
Alerts without noise
An alert fires when a friend enters the radius. It does not fire again while the friend stays inside.
A friend on the edge can cross in and out. A short wait before alerting stops the flutter.
Alerts check cell changes, not every update. That keeps alert cost tied to real movement.
Evaluation and trade-offs
Freshness trades against battery and write load. A 60 second gap is the chosen balance.
Rough distances trade usefulness against safety. Bands answer the question without handing over a location.
Checking friends after the cell lookup keeps work small. The cell lookup returns few candidates, and the friend check runs on those few.
Availability matters less than correctness here. A late answer about location is worse than no answer.
Nearby Friends in numbers
| Item | Figure |
|---|---|
| Users | 1,000,000,000 |
| Sharing location | 100,000,000 |
| Location updates a second | 1,666,667 |
| Update gap per user | 60 seconds |
| Friends per user | 300 |
| One stored location | 16 bytes |
| Latest locations stored | 1,600,000,000 bytes |
Exercise
When does a location update trigger friend checks in this design?