대규모 시스템 설계 기초 2 (6장)
가상 면접 사례로 배우는 대규모 시스템 설계 기초 2 (6장) 의 내용 중, 인상적이었던 부분을 발췌 및 요약합니다.
광고 클릭 이벤트 집계
디지털 광고에서, 데이터의 정확성은 중요하다. 온라인 광고가 얼마나 효율적인지를 알아야 정확한 단가를 매길 수 있기 때문이다.
데이터를 질의하기 위한 요구사항은 다음과 같을 것이다.
- 지난 M 분 동안 ad_id 에 발생한 클릭 수 집계
- 지난 M 분 동안 가장 많은 클릭이 발생한 상위 N 개 ad_id 목록 반환
- 다양한 속성을 기준으로 집계 결과를 필터링하는 기능 지원
이 요구사항을 충족할 api 는 2개다.
- 지난 M 분간 각 ad_id 에 발생한 클릭 수 집계
- 지난 M 분간 가장 많은 클릭이 발생한 상위 N 개 ad_id 목록
데이터 모델
이 시스템에서 데이터는 2종류다. 원시데이터와 집계데이터다.
원시데이터
원시데이터는 말 그대로, 로그 파일에 포함된 광고가 언제 누군가에 의해서 클릭됐는지를 기록하는 것이다.
집계 데이터
집계데이터는 광고 클릭 이벤트를 바탕으로 집계한 결과이다.
원시 데이터와 집계 데이터 둘 다 저장해야 한다.
데이터베이스
어떤 데이터베이스를 사용하는 것이 좋을까? 일단 서비스는 쓰기 중심이다. 매우 많은 클릭 이벤트가 발생하는 것이 예상된다. 그리고, 클릭 이벤트는 시계열을 가진다.
시계열 질의에 최적화된 카산드라나 InfluxDB 를 사용하는 것이 바람직하다.
세그먼트 단위로 분리된 파일을 쓰는 것으로 원시 데이터를 저장하는 방법도 고려해볼만하다.
개략적 설계안
데이터의 처리를 비동기식으로 처리하는 것이 좋을 것이다. 생산자와 소비자 용량이 같을 수 없기 때문이다. 카프카 같은 메시지 큐를 도입해보자.
로그 모니터 — 메시지 큐 — 데이터 집계 서비스 — 메시지 큐 —- 집계 데이터 저장
이러한 형태로 구성되는 것이 대략적인 형태일 것이다.
집계 서비스
집계 서비스로는 맵 리듀스 프레임워크를 사용해보자. 맵 리듀스 프레임워크는 유향 비순환 그래프(DAG)다. 각각의 노드를 두어서 순차적으로 데이터를 필터링하고 변환하는 작업을 하는 것이다.
맵 노드
데이터 출처(카프카)에서 읽은 데이터를 필터링한다. 예를 들어 집계 노드가 3개라면, 읽은 데이터를 3개의 노드에 적절히 분배해줘야 할 것이다. ad_id % 3 과 같은 방식으로 말이다.
집계 노드
집계 노드는 ad_id 별 광고 클릭 이벤트 수를 집계한다.
리듀스 노드
리듀스 노드는 집계 노드가 산출한 결과를 최종 결과로 축약한다. 각각의 집계 노드에서 가장 많은 클릭이 발생환 광고를 리듀스 노드로 보내면, 리듀스 노드에서는 모든 결과를 바탕으로 최종적으로 top 3 의 광고를 뽑는다. DAG 는 맵리듀스 패러다임을 표현하기 위한 모델이다. 빅데이터를 입력으로 받아 병렬 분산 컴퓨팅을 수행한다.
모델의 중간 데이터는 메모리에 저장될 수 있고, 노드간 통신은 TCP 로 이루어질 수도 있고, 공유 메모리를 사용할 수도 있다.(서로 다른 스레드에서 실행되는 경우)
데이터 필터링을 적용하고, 그 결과를 집계할 수도 있을 것이다. 이 때 데이터 필터를 차원(dimension) 이라 부른다. 디멘션을 통과한 데이터는 적절한 결과만 남아서 저장된다.
스트리밍 vs 일괄 처리
본 설계는 스트림 처리와 일괄 처리 방식을 모두 사용된다. 스트림 처리는 데이터를 오는 대로 처리하고, 집계 결과를 생성한다. 일괄 처리는 이력 데이터(원시 데이터)를 백업하기 위해 활용한다.
이렇게 두 처리를 모두 지원하는 시스템 아키텍쳐를 람다라고 부른다.
데이터 재계산
집계한 데이터를 다시 계산해야 하는 경우도 있다. 원시 데이터 저장소에서 데이터를 검색하고, 일괄 처리 프로세스를 따라야 할 것이다. 추출된 데이터는 전용 집계 서비스로 전송된다. 전용 집계 서비스를 구성하는 이유는, 실시간 데이터 처리에 미치는 영향을 없애기 위해서다.
시간
집계를 할 때는 타임스탬프가 필요하다. 타임스탬프는 2종류가 있을 것이다.
- 이벤트 시각 : 광고 클릭이 발생한 시각
- 처리 시각 : 집계 서버거 클릭 이벤트를 처리한 시스템 시각
비동기 처리환경이므로, 이벤트 발생 시각과 처리 시각 사이의 격차는 매우 크다. 데이터 정확도를 위해서는 이벤트 발생 시각을 사용할 것이 좋다.
시스템에 늦게 도착한 이벤트를 올바르게 처리하기 위해서는 워터마크라는 기술을 일반적으로 사용한다. 이는 각 윈도 마지막에 추가 시간을 주는 것이다. 이를 통해서 집계 윈도의 확장으로, 결과의 정확도를 높일 수 있다.
집계 윈도
고정 윈도 방식과, 슬라이딩 윈도 방식이 있을 것이다. 고정 윈도는 같은 크기의 겹치지 않는 시간으로 분할한다. 슬라이딩 윈도는 서로 겹칠 수 있는 윈도로, 구간 안에 이벤트를 집계한다.
M 분간 가장 많으 클릭된 상위 N 개 광고를 알아내기 위해서는 슬라이딩 윈도 방식이 적합하다.
전달 보장
카프카에서 ‘정확히 한 번’ 처리되기를 원한다면 어떻게 해야 할까. 집계 서비스 노드는 업스트림(카프카)에서 데이터를 오프셋을 기준으로 가져온다. 그렇다면 오프셋을 어딘가에 저장해둠으로서 집계 서비스에서 장애가 발생하는 상황을 대응할 수 있을까?
이는 절반의 해결책이다. 가져온 순간의 오프셋과, 처리 완료 후 집계 결과 전송이 끝난 순간의 오프셋을 모두 기록해야 한다. 단계별로 나타내자면 다음과 같다.
- 집계 서비스 노드에서 업스트림(카프카)으로부터 이벤트 수집
- 오프셋을 기준으로 전달 받음
- 오프셋 저장
- 이벤트 집계 처리
- 집계 결과를 다운스트림(카프카)에게 전송
- 오프셋 저장
- 다운스트림으로부터 수신 확인 응답 전송
- 업스트림에 새로운 오프셋으로 이벤트 수집
이 때, 5번부터 7번 사이의 작업은 하나의 분산 트랜잭션에 넣어야 한다.