근접 서비스(Proximity Service)는 사용자 위치를 기반으로 주변 장소나 서비스를 탐색하는 시스템이다. Yelp, Google Places, 배달의민족 지도 검색 등이 대표적이다.
핵심 요구사항
기능:
- 현재 위치 기준 반경 N km 내 장소 검색
- 카테고리/키워드 필터
- 장소 상세 정보 조회
규모:
- 장소 데이터: 5억 개 (읽기 중심)
- QPS: 5,000 (검색), 50 (쓰기)
- 지연시간: 200ms 이하
지리적 인덱싱 전략
1. 균등 격자(Even Grid): 단순, 데이터 불균형
2. GeoHash: Base32 인코딩, 계층적 분할
- 접두사 공유 = 근접 지역
- 단점: 경계 문제 (neighboring cells 추가 조회)
3. QuadTree: 밀도 기반 동적 분할
- 리프당 최대 100개 장소
- 도시: 더 깊은 트리, 농촌: 얕은 트리
4. H3 (Uber): 육각형 격자, 균등 면적
GeoHash 검색 로직
python
import geohash2 as gh
def search_nearby(lat: float, lon: float, radius_km: float):
# 반경에 따른 GeoHash 정밀도 선택
precision = get_precision(radius_km)
# 예: 반경 1km → precision 6 (약 1.2km × 0.6km)
center_hash = gh.encode(lat, lon, precision=precision)
# 중심 + 8방향 인접 셀 (경계 문제 해결)
neighbors = gh.neighbors(center_hash) + [center_hash]
# 각 셀의 장소 조회 (Redis GeoSearch 또는 DB)
places = []
for cell in neighbors:
places.extend(get_places_by_geohash(cell))
# 정확한 거리 계산으로 필터링
return [p for p in places if haversine(lat, lon, p.lat, p.lon) <= radius_km]
시스템 구성
[Client] → [API Gateway] → [Location Service]
↓
[GeoHash Index (Redis)]
[Place Service (캐시)]
↓
[Place DB (MySQL)]
Redis GeoSearch:
GEOADD places 126.978 37.566 "restaurant_1"
GEORADIUS places 126.978 37.566 1 km COUNT 20
캐싱 전략
장소 데이터: 읽기 중심 → Replica 활용
GeoHash 결과: Redis (TTL 10분)
인기 지역: CDN 엣지 캐싱
쓰기 (새 장소 등록):
DB Write → Invalidate Cache → 비동기 인덱스 업데이트
관련 문서
- •[[design-uber|승차 공유 플랫폼 설계]]
- •[[type-ahead-search|타입어헤드 검색]]
- •[[consistent-hashing|일관 해싱]]