π 1οΈβ£ Introduction
Proximity Service is a key component in many modern applications:
Yelp: Find nearby restaurants and shops
Google Places: Return nearby location data for developers
In this lesson, we will design a high-availability, high-performance, scalable proximity service.
π― 2οΈβ£ Requirements Analysis
β Functional Requirements
1οΈβ£ Given a userβs location (latitude, longitude) and a search radius, return nearby businesses
2οΈβ£ Business owners can create, update, delete businesses (updates can appear next day β no real-time requirement)
3οΈβ£ Users can view detailed business information
π Non-Functional Requirements
Low latency: Users should get quick responses
High availability: Handle traffic spikes
System scale:
100 million DAU
200 million businesses
Average QPS β 5,000
π§© 3οΈβ£ High-Level System Architecture
The system consists of two main services:
1οΈβ£ Location-Based Service
Handles proximity queries
Read-heavy, write-free
Horizontally scalable (Stateless)
2οΈβ£ Business Service
Handles CRUD operations on business data
Write traffic is low; reads can be optimized with caching
API Design
GET /nearby
Input: latitude, longitude, radius
Output: List of nearby businesses
Note: Pagination omitted for simplicity; should be included in production
CRUD API
For managing business objects
Business detail requires a separate API call
ποΈ 4οΈβ£ Database Design
Business Table
Stores detailed business information
Estimated size β 1~2 TB
Geospatial Index Table
Columns: geohash + business_id (optional: latitude/longitude)
Estimated size β 6 GB
Can fit in memory; use Read Replicas for read scalability
π 5οΈβ£ Geohash β How It Works
Principle:
1οΈβ£ Alternate binary partitioning of latitude and longitude
2οΈβ£ Generate a 01 sequence based on whether each value falls into lower/upper half of its range
3οΈβ£ Every 5 bits β encode to base32 character β Geohash string
4οΈβ£ Use prefix matching + 8 neighboring grids to query nearby businesses
Benefits:
β Fast lookup with simple DB indexing
β Works with common relational databases
β Naturally supports different search radii through variable Geohash precision
Cautions:
Must query 8 neighboring grids to avoid missing edge cases
Grid distortion at high latitudes
π¦ 6οΈβ£ Sample Query Flow
User searches for restaurants within a 500m radius:
1οΈβ£ Determine appropriate Geohash precision (length 6 β 500m)
2οΈβ£ Query the current Geohash grid and its 8 neighbors
3οΈβ£ Retrieve business IDs and coordinates
4οΈβ£ Calculate actual distance β rank β return results
π§βπ» 7οΈβ£ Geohash Encoding Pseudocode (Java Style)
public class GeohashEncoder {
private static final String BASE32 = "0123456789bcdefghjkmnpqrstuvwxyz";
public static String encode(double latitude, double longitude, int precision) {
double[] latRange = { -90.0, 90.0 };
double[] lngRange = { -180.0, 180.0 };
boolean isEven = true;
int bit = 0;
int ch = 0;
StringBuilder geohash = new StringBuilder();
int[] bits = { 16, 8, 4, 2, 1 };
while (geohash.length() < precision) {
double mid;
if (isEven) {
mid = (lngRange[0] + lngRange[1]) / 2;
if (longitude > mid) {
ch |= bits[bit];
lngRange[0] = mid;
} else {
lngRange[1] = mid;
}
} else {
mid = (latRange[0] + latRange[1]) / 2;
if (latitude > mid) {
ch |= bits[bit];
latRange[0] = mid;
} else {
latRange[1] = mid;
}
}
isEven = !isEven;
if (bit < 4) {
bit++;
} else {
geohash.append(BASE32.charAt(ch));
bit = 0;
ch = 0;
}
}
return geohash.toString();
}
// Example usage
public static void main(String[] args) {
String geohash = GeohashEncoder.encode(37.4219999, -122.0840575, 6);
System.out.println("Geohash: " + geohash);
}
}
π 8οΈβ£ Summary
This lesson walks through the core design of a Proximity Service:
Service decomposition (Location vs Business)
Geohash-based spatial indexing
Storage optimization
Scalability considerations (read replicas, caching)
These design patterns are applicable to many real-world applications like Yelp, Google Places, Uber, DoorDash, and other location-based services ππ.