일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- AWS
- 클라우드자격증
- 추천시스템
- 머신러닝
- llm
- chatGPT
- COFIBA
- 머신러닝 파이프라인
- Collaborative Filtering Bandit
- 클라우드
- 자연어처리
- RecSys
- nlp
- 미국석사
- 플랫폼
- MAB
- docker
- BERT이해
- 네트워크
- 중국플랫폼
- HTTP
- MLOps
- 언어모델
- MSCS
- TFX
- BANDiT
- 메타버스
- transformer
- aws자격증
- BERT
- Today
- Total
Julie의 Tech 블로그
근접성 서비스(Proximity Service) - 지오해시, 쿼드트리, S2 본문
본 글은 아래 책을 읽고 요약된 정보입니다.
https://product.kyobobook.co.kr/detail/S000211656186
개요
- 현재 위치에서 가장 가까운 시설을 찾는 서비스를 개발
- 핵심기능
- 사용자 위치 정보와 검색 반경에 매치되는 사업장 목록 반환
- 사업장 소유주가 사업장 정보를 추가/삭제/갱신할 수 있지만 검색 결과에 실시간 반영될 필요는 없음
- 고객은 사업장의 상세 정보를 살필 수 있어야함
- 비기능 요구사항(non-functional requirements)
- 낮은 응답 지연: 사용자가 주변 사업장을 신속히 검색 가능해야함
- 데이터 보호: 사용자 위치 정보는 민감한 개인정보
- 고가용성, 규모 확장성: 인구 밀집 지역에서 트래픽 감당해야함
- 개략적 규모 추정
- DAU 1억명, 사업장 수 2억
- 핵심기능
설계안
- API 설계
- GET /v1/search/nearbytotal 개수와 business 객체를 output으로 뱉음
- 검색결과 페이지에서 노출할 용도
- latitude, longitude, radius를 인자로 받음
- GET /v1/businesses/:idPUT /v1/businesses/:id특정 상세 정보 반환과 사업장 추가/갱신/삭제 API
- DELETE /v1/businesses/:id
- POST /v1/businesses
- 데이터 모델
- 데이터 스키마
- business_id가 PK인 테이블과 지리적 위치 색인 테이블이 필요함
- read 연산이 상대적으로 훨씬 많기 때문에 MySQL 관계형 DB를 추천
- 위치 기반 서비스 (Location based service)
- 특징QPS가 높음. 특정 시간대의 인구 밀집 지역일수록 경향이 심함
- 무상태(stateless)서비스이므로 수평적 규모 확장이 쉬움
- 쓰기 요청은 없음, 읽기 요청 빈번
- 사업장 서비스
- 특징사업장 소유주가 사업장 정보를 생성,갱신,삭제함. 이 때는 쓰기 요청이며 QPS가 높지 않음
- 고객이 사업장 정보 조회하면 특정 시간대에는 QPS가 높음
- 데이터 베이스
- primary-secondary 구조를 지님. 실시간 갱신일 필요는 없기 때문에 secondary DB로의 복제에 걸리는 delay는 해결 가능
- Auto scaling, high availability
- LBS와 사업장 서비스 모두 stateless하기 때문에 추구 가능
주변 사업장 검색 알고리즘
- 대다수가 Geohash in Redis나 PostGIS DB를 사용함
- 이 때 SQL문도 어떻게 만들 것인지에 따라 DB색인구조를 고민해볼 수 있음
- 위도 컬럼과 경도 컬럼에 색인을 만들어둔다. 이 경우 각각 집합에 대한 요소는 빠르게 추출이 가능하지만 반경 내 사업장을 얻으려면 두 집합의 교집합을 구해야한다. 이 때는 각 집합에 속한 데이터 양때문에 비효율적이게 됨.
- 1안은 채택 불가. 대부분 널리 사용되는 알고리즘은
- 해시 기반 방안: even grid, geohash, cartesian tiers
- 트리 기반 방안: quadtree, 구글 s2, R-tree
Even grid
전체 지도를 평평하게 둔 후 위도, 경도로 분할. 이 때 밀집도가 다르다는 단점
Geohash
전 세계를 자오선과 적도 기준 사분면으로 나눔. 위도, 경도 값을 hashing하여 1차원 문자열로 변환. 재귀적으로 사분면을 분할해나가 precision을 확보할 때까지 분할
- 위도 [-90,0]은 0에 대응, 위도 [0,90]은 1에 대응
- 경도 [-180,0]은 0에 대응, 경도 [0,180]은 1에 대응
base32 표현법을 사용
최적 정밀도는 사용자가 지정한 반경으로 그린 원을 덮는 최소 크기 격자를 만드는 지오해시 길이를 구해야함
→ 격자 가장자리 관련 이슈가 있음
- 지오해시는 해시값의 공통 접두어(prefix)가 긴 격자들이 서로 더 가깝게 노이도록 보장함
하지만 그 역은 참이 아님. 가령 가까운 두 위치가 어떤 공통 접두어도 갖지 않는 일이 발생할 수도 있음
두 지점이 적도의 다른쪽에 놓이거나 자오선상의 다른 반쪽에 놓이는 경우
이 한계 때문에 접두어 기반 SQL 질의문을 사용하면 주변 모든 사업장을 가져올 수 없음
- 두 지점이 공통 접두어 길이는 길지만 서로 다른 격자에 놓이는 경우
이 때문에 흔히들 현재 격자를 비롯한 인접 모든 격자의 사업장 정보를 가져옴
- 만약 표시할 사업장 수가 많지 않은 경우
- 주어진 반경 내 사업장만 반환
- 검색 반경을 재귀적으로 키움
Quadtree
quadtree는 격자의 내용이 특정 기준을 만족할 때까지 2차원 공간을 재귀적으로 사분면 분할
데이터베이스 구조가 아니라 메모리에 놓인 자료 구조임
- pseudo code
- public void buildQuadtree(TreeNode node) if (countNumberOfBusinessInCurrentGrid(node) > 100) { node.subdivide(); for (TreeNode child : node.getChildren()) { buildQuadtree(child); } } }
이 때 쿼드트리를 저장하는데 소비될 메모리 양을 계산하려면 어떤 데이터가 보관될지 정해야함
- 밑단 노드: 격자 식별자(좌상단&우하단 좌표), 격자 내 사업자 ID목록
- 내부 노드: 격자 식별자, 하위 노드 4개를 가르킬 포인터
- 내부 노드의 수는 말단 노드 수의 1/3
각 노드의 메모리 총량 합계와 밑단, 내부 노드 수르 곱하면 총 메모리 요구량이 나옴
이 때 밑단 노드에 저장될 사업장의 최대 개수는 앞서 ‘특정 기준’과 동일하니 계산이 가능
그럼 전체 quadtree를 저장하는데 소요되는 시간 복잡도: n/100 * log n/100
따라서 서버를 시작하는 순간에 트리를 구축하면 서버 시작 시간이 너무 길어짐. 이 시간 동안은 트래픽을 처리할 수 없기 때문에 새로운 버전의 소프트웨어를 릴리즈 할 때는 너무 많은 서버에 동시 배포하지 않도록 주의
blue/green deployment 방안 - production 환경의 절반 가량을 실제 서비스가 아닌 신규 이미지 테스트에만 사용
따라서 quadtree를 갱신할 때에도 old data를 반환하는 기준이 너무 critical하지 않다면 점진적으로 서버를 갱신할 것
구글의 S2
S2 geometry 라이브러리는 이 분야에서 아주 유명한 솔루션
quadtree와 마찬가지로 이 방법도 in-memory 기반
힐베르트 곡선이라는 space-filling curve를 사용하는데, 곡선 상에서 인접한 두 지점이 1차원 공간 내에서도 인접한 위치에 두도록 함
1차원 공간 내의 검색은 2차원 공간에서의 검색보다 훨씬 더 효율적임
Geofence
세계 지리적 영역에서 설정한 가상의 경계, 예를 들어 school zone이나 동네 경계와 같이 이미 존재하는 경계선들을 묶을 수 있음
이 때 사용자가 해당 경계를 벗어나면 알림을 보내는 등 단순 주변 사업장 검색보단 훨씬 풍부한 기능 제공이 가능하다
Geohash vs Quadtree
지오해시 쿼드트리
구현과 사용이 쉬움. 트리 구축 필요 X | 구현하기가 살짝 더 까다로움. 트리 구축이 필요 |
지정한 반경 이내 사업장 검색 지원 | k번째로 가까운 사업장까지의 목록을 구할 수 있음 |
예를 들어 가는 길에 가까운 주유소 찾기 등 | |
정밀도를 고정하면 격자 크기도 고정됨 | 색인 갱신 과정이 까다로움. |
트리 자료 구조이기 때문에 말단 노드까지 순회해야함. | |
이 때 multi-thread 방식이라면 lock을 구현해야하기 때문에 복잡해질 수 있음 | |
그리고 트리 균형을 다시 맞추는 re-balancing 과정이 있어야할 수도 | |
색인 갱신이 쉬움 | |
예를 들어 삭제시 지오해시값과 사업장 식별자가 같은 열 하나만 제거하면 됨 |
데이터베이스 규모 확장성
- Business 테이블은 샤딩을 적용하기 좋은 후보
- 지리 정보 색인 테이블
- 지오해시인 경우 각 지오해시에 연결되는 모든 사업장 ID를 JSON 배열로 만들어 동일 열에 저장
- 이 경우에는 샤딩을 적용하는 것이 좋지 않을 수 있음. 왜냐하면 application layer에서 구현해야하기 때문
- 따라서 읽기 부하를 감당할 수 있는 사본 데이터베이스를 두는 방법이 좋을 것
캐시
- 정말 캐시가 필요할까? 라는 질문을 던질 필요가 있음
- 만약 보관하게 된다면 지오해시에 대응되는 사업장 목록을 저장한다면 좋을 듯
- 사용자 위치 정보를 해시 키로 두는 것은 옳지 않음
- 지역 및 가용성 구역
- 일본이나 한국과 같은 경우 인구 밀도가 높기 때문에 트래픽을 인구에 따라 유연하게 분산할 필요가 있음
'Tech' 카테고리의 다른 글
주변 친구 찾기 - 웹소켓, Redis, Redis Pub/Sub (0) | 2024.02.15 |
---|---|
LLM OS? 언어모델이 제시하는 새로운 패러다임 (1) | 2023.11.25 |
Vector Store: Azure Vector Search에 대하여 (0) | 2023.08.22 |
[UIUC MCS 회고] 대학원을 졸업하며.. (8) | 2023.08.10 |
ChatGPT Plugin이란, 구축 방법 (0) | 2023.04.25 |