원제: 가상 면접 사례로 알아보는 대규모 설계 시스템 기초2
- 주변 사업장 검색
- 레디스 GeoHash나 포스티그레스 PostGis를 주로 사용
- 지리 정보 색인 방법
- 지도를 작은 영역으로 분할하고 고색 검색이 가능하도록 색인하는 방법
- 해시 기반
- 균등 격자: 지도를 작은 격자, 구획으로 단순히 분할
- geoHash: 2차원 위도,경도 데이터를 1차원 문자열로 변환
- 비트를 하나씩 늘려가며 재귀적으로 더 작은 격자로 분할
- 카르테시안 계층
- 트리 기반
- 쿼드 트리: 격자의 내용이 특정 기준을 만족할때까지 2차원 공간을 재귀적으로 사분면 분할
- 구글 S2, R-tree 등등
- GeoHash Vs 쿼드 트리
- GeoHash는 구현과 사용이 쉬우나 정밀도가 고정된다
- GeoHash는 색인 갱신이 매우 쉽다. 그러나 샤딩은 어렵다
- 쿼드 트리는 정밀도가 유연하게 변경이 가능하다
- 쿼드 트리는 K번째 가까운 사업장같은 목록 계산이 가능하나 색인 갱신이 어렵다
- 주변 친구 찾기
- 웹 소켓을 통한 실시간 주변 친구의 접속 여부를 찾을 수 있도록 해야 한다
- redis pub/sub와 같은 경량 메시지 버스를 이용하여 사용자의 위치 이동을 다른 사용자에게 빠르게 알려야 한다
- 사용자의 위치 이동 이력은 카산드라와 같은 막대한 쓰기 부하를 견딜 수 있는 데이터베이스를 사용해야 한다
- 어플리케이션 이용에는 크게 관계가 없으나 데이터/마케팅 팀에서 활용이 가능하기 때문
- 구글 맵
- 지오 해시와 최단 경로 알고리즘을 이용한 길 찾기를 지원하는 설계 문제
- 그래프 db를 이용한 경로 및 노드, 가중치 관리
- 최단 경로 알고리즘: A(Star)*, 다익스트라 를 주로 이용
- 분산 메시지 큐
- 발행-구독 모델은 토픽을 통해 구현하고, 일대일 모델은 소비자 그룹을 통해 구현한다
- 병렬로 데이터를 읽을 때 소비자가 여러명인 경우 순서를 보장 할 수 없다
- 카프카의 경우 토픽-그룹 개념을 통해 그룹 당 한 소비자만 한 파티션을 읽도록 하여 해결
- 한 번에 여러 메시지를 읽는 배치 방식을 통해 높은 대역폭을 유지하거나, 한 개의 메시지를 빠르게 읽게 하여 낮은 응답 지연을 얻을 수 있다
- 라우팅 계층
- 어떤 파티션에 메시지를 보내야 할 때 브로커를 지정하기 위한 계층
- 이를 생산자 라이브러리에 통합하고 버퍼를 도입하면 네트워크 오버헤드 감소, 대역폭 증가와 같은 효과를 누릴 수 있다
- 대부분의 메시지 큐는 푸시 모델보다는 풀 모델을 선택하는데 컴퓨팅 자원을 줄이기 위해 롱-풀링을 사용한다
- 이는 생산자의 생산 속도에 소비자가 압도당해 생기는 문제를 줄이기 위함
- ISR(In Sync Replicas)
- 리더와 동기화된 사본(브로커)를 지칭하는 용어
- 설정값으로 정해진 숫자보다 적은 숫자의 동기화 차이를 보이는 브로커 그룹을 지칭
- 성능과 영속성의 타협
- ACK 옵션을 통해 성능을 높이거나 영속성을 높이는 선택을 할 수 있다
- 지연 발송 기능은 메시지 큐를 이용하기 보다 임시 저장소를 이용하여 저장 후 해당 토픽에 발송하는 것이 유용하다고 생각한다
- 복잡한 메시지 필터링 기능을 제공하는 것은 메시지 큐의 성능을 낮출 수 있으므로 차라리 소비자 discard(버림) 하거나 특정 tag만 구독하게 하는 간단한 방식이 더 많이 사용된다
- 지표 모니터링 및 경보
- 데이터 수집, 전송, 저장소, 경보, 시각화와 같은 컴포넌트를 베이스로 구성한다
- 지표 데이터는 통상 시계열 데이터를 이용하므로 시계열 데이터베이스가 저장소로 유용하다
- 고릴라, 프로메테우스, influxDB 등이 주로 사용된다
- 수집 방식
- 풀 모델: 대상 서버에 정의된 주소를 통해 일정 주기로 수집하는 방식
- 푸시 모델: 대상 서버에 수집 에이전트를 설치하는 방식을 많이 사용한다
- 다운 샘플링
- 데이터의 해상도를 낮춰 저장소 요구량을 줄이는 기법
- 통상 특정 주기가 지난 데이터를 평균 값으로 변경하여 저장하는 방식
- 광고 클릭 이벤트 집계
- 광고 클릭 데이터는 원시 데이터와 집계 데이터 둘 다 저장하는 것이 좋다 → 문제 발생 시 디버깅 및 복구와 집계의 성능 향상 둘 다 얻을 수 있다
- 원시 데이터는 일반적으로 대용량 쓰기에 적합한 데이터 베이스를 사용한다
- 집계 서비스는 무한한 데이터의 스트림이므로 Map-Reduce 프레임 워크를 이용하여 집계하는데 좋은 방안이 될다
- 카파 아키텍처
- 일괄 처리와 스트리밍 처리 경로를 분리되어 관리가 어려운 람다 아키텍쳐의 개선
- 단일 스트림 처리 엔진을 사용하여 실시간 데이터 및 데이터 재처리 문제를 해결
- 윈도우 방식에서는 워터마크(여분의 시간)을 이용하여 늦게 도착한 이벤트를 처리한다
- 조정(reconciliation)처럼 다양한 데이터를 비교하여 데이터 무결성을 보증하는 작업이 필요하다
- 호텔 예약 시스템
- 읽기 빈도가 높아 주로 관계형 데이터베이스를 사용한다
- 이중 예약 방지를 위해 예약 API 요청에 멱등키를 발급하여 사용한다
- 전역 키를 이용하여 예약 주문서에 진입할 때 발급해 준다
- 같은 방에 대한 예약 경쟁이 치열하지는 않으므로 비관적 락 보다는 낙관적 락이 성능면에서 유용하여 주로 사용된다
- 분산 이메일 서비스
- 프로토콜
- SMTP: 한 서버에서 다른 서버로 보내는 표준 프로토콜
- POP: 클라이언트가 원격 메일 서버에서 이메일을 수신하고 다운로드하기 위해 사용하는 표준 프로토콜
- 다운로드된 메일은 서버에서 삭제되며 한번에 모든 내용을 받아야 한다
- IMAP: 클라이언트가 이메일을 수신하기 위한 다른 표준 프로토콜
- POP와는 달리 클릭하지 않으면 메시지는 다운로드되지 않고 서버에서 삭제되지도 않는다
- 클릭하기 전에는 헤더만 다운로드하여 목록을 보여줄 수 있다
- 저장소 요구사항이 특이하여 독자적인 데이터베이스를 사용하여 구축하는 경우가 많다
- 대규모 성능을 위해 읽은 메일, 읽지 않은 메일로 분류하여 비 정규화된 테이블을 유지하는 경우가 많다
- 이메일 스레드는 JWZ 같은 알고리즘을 이용하여 구현하는 경우가 많다
- 객체 저장소
- 저장소 시스템 분류
- 블록 저장소: 원시 블록을 서버에 볼륨 형태로 제공하는 형태의 저장소
- 파일 저장소: 블록 저장소 위에서 파일과 디렉토리를 손쉽게 다루는데 필요한 더 높은 수준의 추상화를 제공하는 저장소
- 객체 저장소: 데이터 영속성을 높이고 대규모 어플리케이션을 지원하기 위해 의도적으로 성능을 희생한 저장소
- 메타데이터와 데이터를 분리하여 저장해서 설계를 단순화하고 변경에 이점을 가지는 것이 좋다
- 작은 파일을 매번 디스크에 별도로 저장하면 I-Node 고갈이 일어남으로 여러 파일을 묶어서 저장하는 것이 효율적이다
- 소거 코드
- 실시간 게임 순위표
- 결제 시스템
- 전자 지갑
- 증권 거래소