읽은 책/[책] 가상 면접 사례로 배우는 대규모 시스템 설계 기초 2권

6장. 광고 클릭 이벤트 집계

코드몬스터 2024. 8. 15. 22:53
728x90

페이스북이나 구글 규모에 걸맞는 광고 클릭 이벤트 집계 시스템을 설계한다.

온라인 광고의 핵심적 혜택은 실시간 데이터를 통해 광고 효과를 정량적으로 측정할 수 있다는 것이다.

디지털 광고의 핵심 프로세스는 RTB(Real-Time Bidding), 즉 실시간 경매라고 부르고 RTB 프로세스는 1초내에 모든 프로세스가 마무리된다.

 

데이터의 정확성도 중요하다. 광고 클릭 이벤트 집계는 온라인 광고가 얼마나 효율적이었는지 측정하는데 결정적인 역할을 하며, 광고주가 얼마나 많은 돈을 지불할지에 영향을 끼친다.

클릭 집계 결과에 따라 광고 캠페인 관리자는 광고 예산을 조정하기도 하고, 타깃 그룹이나 키워드를 변경하는 등 광고 전략을 수정하기도 한다.

 

핵심 지표는 CTR(Click-Through Rate, 클릭률), CVR(Conversion Rate, 전환률) 등이 있다.


1단계: 설계 범위

1. 기능 요구사항

  • 지난 M분 동안의 ad_id 클릭 수 집계
  • 매분 가장 많이 클릭된 상위 100개 광고 아이디를 반환
  • 다양한 속성에 따른 집계 필터링을 지원
  • 데이터의 양은 페이스북이나 구글 규모

2. 비기능 요구사항

  • 집계 결과 적황성은 데이터가 RTB 및 광고 과금에 사용되므로 중요
  • 지연되거나 중복된 이벤트를 적절히 처리할 수 있어야함
  • 견고성: 부분적인 장애는 감내할 수 있어야 함
  • 지연 시간 요구사항: 전체 처리 시간은 최대 수 분을 넘지 않아야 함

3. 개략적 추정

  • 일간 능동 사용자 수는 10억명
  • 하루에 10억 건의 광고 클릭 이벤트가 발생
  • QPS = 10,000
  • 최대 광고 클릭은 평균의 다섯배 = 50,000QPS로 가정
  • 광고 클릭 이벤트 하나당 0.1KB의 저장 용량이 필요
    • 일 저장 요구량은 0.1KB * 10억 = 100GB
    • 월 저장 요구량은 대략 3TB

2단계: 개략적 설계안

1. 질의API 설계

본 설계안의 클라이언트는 대시보드를 이용하는 데이터 과학자, 제품 관리자, 광고주 같은 사람들이다.

그들이 대시보드를 이용하는 순간 집계 서비스에 질의가 발생한다.

  • 지난 M분 동안 각 ad_id에 발생한 클릭 수 집계
  • 지난 M분 동안 가장 많은 클릭이 발생한 상위 N개 ad_id 목록 반환
  • 다양한 속성을 기준으로 집계 결과를 필터링하는 기능 지원

API 1: 지난 M분간 각 ad_id에 발생한 클릭 수 집계

API 용도
GET /v1/ads/{:ad_id}/aggregated_count 주어진 ad_id에 발생한 이벤트 수를 집계하여 반환

 

호출 인자

인자명 자료형
from 집계 시작 시간 long
to 집계 종료 시간 long
filter 필터링 전략 식별자 long

 

반환 응답

필드명 자료형
ad_id 광고 식별자 string
count 집계된 클릭 횟수 long

 

API 2: 지난 M분간 가장 많은 클릭이 발생한 상위 N개 ad_id 목록

API 용도
GET /vi/ads/popular_ads 지난 M분간 가장 많은 클릭이 발생한 상위 N개 광고 목록 반환

 

호출인자

인자명 자료형
count 상위 몇 개의 광고를 반환할 것인가 integer
window 분 단위로 표현된 집계 윈도 크기 integer
filter 필터링 전략 식별자 long

 

반환 응답

필드명 자료형
ad_ids 광고 식별자 목록 array

2. 데이터 모델

데이터는 원시데이터와 집계 결과 데이터로 나눌 수 있다.

 

원시 데이터

[AdClickEvent] ad001, 2021-01-01 00:00:01, user 1, 207.148.22.22, USA

 

집계 결과 데이터

광고 필터링을 지원하기 위해 이 테이블에 filter_id를 추가한다.

ad_id click_minute filter_id count
ad001 202101010000 0012 2
ad001 202101010000 0023 3
ad001 202101010001 0012 1

 

비교

둘 다 저장하는 것을 추천한다.

  • 문제가 발생하면 디버깅에 활용할 수 있도록 원시 데이터도 보관
  • 원시 데이터는 양이 엄청나므로 직접 질의하는 것은 비효율적
  • 원시 데이터는 백업 데이터로 활용된다.
  • 집계 결과 데이터는 활성 데이터 구실을 한다.
  원시 데이터만 보관하는방안  집계 결과 데이터만 보관하는 방안
장점 원본 데이터를 손실 없이 보관
데이터 필터링 및 재계산 지원
데이터 용량 절감
빠른 질의 성능
단점 막대한 데이터 용량
낮은 질의 성능
데이터 손실, 원본 데이터가 아닌 계산/유도된 데이터를 저장하는 데서 오는 결과

3. 올바른 데이터베이스의 선택

올바른 데이터를 선택하기 위한 평가 사항

  • 데이터는 어떤 모습인가? 관계형 데이터? 문서 데이터? 이진 대형 객체?
  • 작업 흐림이 읽기 중심인가 쓰기 중심인가? 아니면 둘다 인가?
  • 트랜잭션을 지원해야하는가?
  • 질의 과정에서 분석 처리 함수를 많이 사용해야하는가?

원시데이터는 일상적인 작업을 위해서라면 필요가 없지만, 데이터나 과학자나 기계 학습 엔지니어가 사용자 반응 예측, 행동 타기팅 등을 연구하는데 유용하다.

 

관계형 데이터베이스로도 할 수 있지만 규모 있는 쓰기 연산이 가능하도록 구성하기는 어렵다.

쓰기 및 시간 범위 질의에 최적화된 카산드라나 InfluxDB를 사용하는 것이 좀 더 바람직하다.

 

아마존 S3에 데이터를 저장하는 방법도 있겠지만, 많은 사람들에게 낯설 수 있다.

 

집계 데이터는 본질적으로 시계열 데이터이며, 데이터를 처리하는 워크플로는 읽기 연산과 쓰기 연산을 둘 다 많이 사용한다.

4. 개략적 설계안

실시간으로 빅데이터를 처리할 때 데이터는 보통 무제한으로 시스템에 흘러 들어왔다가 흘러 나간다.

집계 서비스도 마찬가지이다.

집계 워크플로

 

비동기처리

데이터 동기식으로 처리하면 생산자와 소비자 용량이 항상 같을 수는 없으므로 좋지 않다.

 

예를 들어, 트래픽이 갑자기 증가하여 발생하는 이벤트 수가 소비자의 처리 용량을 훨씬 넘어서는 경우에는 소비자는 메모리 부족 오류 등의 예기치 않은 문제를 겪게 될 수 있다.

 

이를 해결하는 일반적인 방안은 카프카 같은 메세지 큐를 도입하여 생산자와 소비자의 결합을 끊는 것이다.

결과로 전체 프로세스는 비동기 방식으로 동작하게 되고, 생산자와 소비자의 규모를 독립적으로 확장해 나갈 수 있게 된다.

 

첫 번째 메세지 큐에 입력되는 데이터

ad_id click_timestamp user_id ip country

두 번재 메세지 큐에 입력되는 데이터

 

1. 분 단위로 집계된 광고 클릭 수

ad_id click_minute count

 

2. 분단위로 집계한, 가장 많이 클릭한 상위 N개 광고

update_time_minute most_clicked_ads

 

개략적 설계안

 

집계 결과를 데이터베이스에 바로 기록하지 않는 이유는 정확하게 한 번 데이터를 처리하기 위해 카프카 같은 시스템을 두 번째 메세지 큐로 도입해야하기 때문이다.

5. 집계 서비스

광고 클릭 이벤트를 집계하는 좋은 방안은 맵리듀스 프레임워크를 사용하는 것이다.

맵 리듀스프레임워크에 좋은 모델은 유향 비순환 그래프(directed arcyclic graph, DAG)다.

DAG의 핵심은 맵/집계/리듀스 노드 등의 작은 컴퓨팅 단위로 세분화하는 것이다.

 

맵노드

  • 맵 노드는 데이터 출처에서 읽은 데이터를 필터링하고 변환하는 역할을 담당한다.
    • 예를 들어, ad_id % 2 = 0의 조건을 만족하는 데이터를 노드 1로 보내고, 아니면 노드 2로 보낸다.
  • 입력 데이터를 정리하거나 정규화해야 하는 경우에는 맵 노드가 필요하다.
  • 데이터가 생성되는 방식에 대한 제어권이 없는 경우에는 동일한 ad_id를 갖는 이벤트가 서로 다른 파티션에 입력될 수도 있다.

집계 노드

  • 집계 노드는 ad_id별 광고 클릭 이벤트 수를 매 분 메모리에서 집계한다.
  • 맵 리듀스 패러다임에서 집계 노드는 리듀스 프로세스 일부이다.

리듀스 노드

  • 모든 집계 노드가 산출한 결과를 최종 결과로 축약한다.
  • 예를 들어, 집계 노드 각각은 자기 관점에서 가장 많은 클릭이 발생한 광고 3개를 추려 리듀스 노드로 보낸다.
  • DAG는 맵리듀스 패러다임을 표현하기 위한 모델이다.
    • 빅데이터를 입력으로 받아 병렬 분산 컴퓨팅 자원을 활용하여 빅데이터를 작은, 또는 일반적인 크기 데이터로 변환할 수 있도록 설계된 모델이다.

주요 사용 사례

사례 1. 클릭 이벤트 수 집계

  • 맵 노드는 시스템에 입력되는 이벤트를 ad_id % 3 을 기준으로 분배하며, 분배한 결과는 각 집계 노드가 집계한다.

사례 2. 가장 많이 클릭된 상위 N개 광고 반환

  • 가장 많이 클릭된 상위 광고 3개를 가져오는 방법에서 상위 N개 광고로도 확장될 수 있다.

사례 3. 데이터 필터링

  • 데이터 필터링을 지원하려면 필터링 기준으로 사전에 정의한 다음에 해당 기준에 따라 집계하면 된다.
  • 이런 기법을 스타 스키마라고 부르고 데이터 웨어하우스에서 널리 쓰이는 기법으로, 필터링에 사용되는 필드는 차원이라고 부른다.

3단계: 상세 설계

1. 스트리밍 vs 일괄 처리

  • 스트림 처리는 데이터를 오는 대로 처리하고 거의 실시간으로 집계된 결과를 생성하는데 사용한다.
  • 일괄 처리는 이력 데이터를 백업하기 위해 활용한다.
  • 일괄 및 스트리밍 처리 경로를 동시에 지원하는 시스템의 아키텍처를 람다(lambda)라고 부른다.
  • 람다 아키텍처의 단점은 두 가지 처리 경로를 지원하므로 유지 관리해야할 코드가 두벌이라는 점이다.
  • 카파 아키텍처는 일괄 처리와 스트리밍 처리 경로를 하나로 결합하여 문제를 해결한다.
  • 핵심 아이디어는 단일 스트림 처리 엔진을 사용하여 실시간 데이터 처리 및 끊임없는 데이터 재처리 문제를 모두 해결하는 것이다.

데이터 재계산

이미 집계한 데이터를 다시 계산해야 하는 경우가 있는데, 이를 이력 데이터 재처리라고 부른다.

 

재계약 흐름

  1. 재계산 서비스는 원시 데이터 저장소에서 데이터를 검색한다.
  2. 추출된 데이터는 전용 집계 서비스로 전송된다. 전용 집계 서비스를 두는 것은 실시간 데이터 처리 과정이 과거 데이터 재처리 프로세스와 간섭하는 일을 막기 위해서이다.
  3. 집계 결과는 두 번째 메시지 큐로 전송되어 집계 결과 데이터베이스에 반영된다.

2. 시간과 집계 윈도

시간

집계를 하려면 두 가지 다른 위치의 타임스탬프가 있다.

  • 이벤트 시각: 광고 클릭이 발생한 시각이다.
  • 처리 시각: 집계 서버가 클릭 이벤트를 처리한 시스템 시각이다.

네트워크 지연이나 비동기적 처리 환경 때문에 이벤트가 발생한 시각과 처리 시각 사이의 격차가 커질 수 있다.

  • 이벤트가 발생한 시각을 집계에 사용하는 경우에는 지연된 이벤트 처리 문제를 잘 해결해야 한다.
  • 처리 시각을 집계에 사용하는 경우에는 집계 결과가 부정확할 수 있다는 점을 고려해야 한다.

완벽한 솔루션은 없다. 두 방안의 장단점을 고려해 적절한 결정을 내려야한다.

 

집계 윈도

  • 텀블링 윈도, 고정 윈도, 호핑 윈도, 슬라이딩 윈도, 세션 윈도가 있다.
  • 텀블링 윈도는 시간을 같은 크기의 겹치지 않는 구간으로 분할한다.
    • 매 분 발생한 클릭 이벤트를 집계하기에 적합하다.
  • 슬라이딩 윈도는 데이터 스트림을 미끄러져 나아가면서 같은 시간 구간 안에 있는 이벤트를 집계한다.
    • 지난 M분간 가장 많이 클릭된 상위 N개의 광고를 알아내기에 적합하다.

3. 전달 보증

집계 결과는 과금 등에 활용될 수 있기 때문에 데이터의 정확성과 무결성이 중요하다.

  • 이벤트의 중복 처리를 어떻게 피할 수 있는가?
  • 모든 이벤트의 처리를 어떻게 보장할 수 있는가?

 

어떤 전달 방식을 택할 것인가?

약간의 중복은 괜찮다면 최소 한 번이 적절하다. 하지만 본 설계안은 데이터의 몇 퍼센트 차이가 수백만 달러 차이로 이어지기 떄문에 정확히 한 번 방식을 권장한다.

 

데이터 중복 제거

  • 클라이언트 측: 한 클라이언트가 같은 이벤트를 여러 번 보내는 경우, 악의적인 의도로 전송되는 중복 이벤트를 처리하는 데는 광고 사기/위험 제어 컴포넌트가 적합하다.
  • 서버 장애: 집계 도중에 집계 서비스 노드에서 장애가 발생하였고 업스트림 서비스가 이벤트 메세지에 대해 응답을 받지 못하였다면, 다시 전송되어 재차 집계될 가능성이 있다.

4. 시스템의 규모 확장

본 설계안은 메세지 큐, 집계 서버, 데이터베이스의 세 가지 독립 구성 요소로 이루어져 있다.

해당 구성 요소들은 상호 결합도가 낮으므로 각기 독립적으로 규모를 늘릴 수 있다.

 

메세지 큐의 규모 확장

생산자: 생산자 인스턴스 수에는 제한을 두지 않으므로 따라서 확장성은 쉽게 달성 가능

소비자: 소비자 그룹 내의 재조정 메커니즘은 노드 추가/삭제를 통해 그 규모를 쉽게 조정할 수 있다.

 

브로커

  • 해시 키
    • ad_id 를 갖는 이벤트를 같은 카프카 파티션에 저장하기 위해 ad_id를 해시 키로 사용한다.
  • 파티션의 수
    • 파티션의 수가 변하면 같은 ad_id를 갖는 이벹트가 다른 파티션에 기록되는 일이 생길 수 있다.
    • 파티션의 수가 동적으로 늘어나는 일은 피하는 것이 좋다.
  • 토픽의 물리적 샤딩
    • 하나의 토픽만으로 충분한 경우는 거의 없다.
    • 지역에 따라, 사업 유형에 따라 여러 포틱을 둘 수 있다.

집계 서비스의 규모 확장

집계 서비스의 처리 대역폭을 높이려는 두 가징 방법

 

방법 1. ad_id마다 별도의 처리 스레드를 두는 방안

방법 2. 집계 서비스 노드를 아파치 하둡 같은 자원 공급자에 배포하는 방식. 다중 프로세싱을 활용하는 방안

 

첫 번째 방안이 구현하기 쉽지만, 많은 컴퓨팅 자원을 추가하여 시스템 규모를 확장할 수 있다.

 

데이터베이스의 규모 확장

  • 카산드라는 안정 해시와 유사한 방식으로 슈평적인 규모 확장을 기본적으로 지원하고 있다.
  • 테이터는 각 노드에 균등하게 분산한다.
  • 각 노드는 해시 링 위의 특정 해시 값 구간의 데이터 보관을 담당하며, 다른 가상 노드의 데이터 사본도 보관한다.

핫스팟 문제

  • 다른 서비스나 샤드보다 더 많은 데이터를 수신하는 서비스나 샤드를 핫스팟이라 부른다.
  • 이벤트 파티션을 ad_id로 나누기 때문에, 어떤 집계 서비스 노드는 다른 노드보다 더 많은 광고 클릭 이벤트를 수신하게 될 것이고, 그러면 서버 과부하 문제가 발생할 수 있다.
  • 처리 순서
    1. 한 노드가 감당할 수 있는 양을 초과하면, 자원 관리자에게 추가 자원을 신청
    2. 자원 관리자는 추가 자원을 할당
    3. 집계 서비스 노드는 이벤트를 세 개 그룹으로 분할
    4. 집계가 끝난 축약된 결과는 다시 원래 집계 서비스 노드에 기록

5. 결함 내성

  • 집계는 메모리에서 이루어지므로 집계 노드에 장애가 생기면 집계 결과도 손실된다.
  • 업스트림 카프카 브로커에서 이벤트를 다시 받아오면 숫자를 다시 만들 수 있다.
  • 업스트림 오프셋 같은 '시스템 상태'를 스냅숏으로 저장하고 마지막으로 저장된 상태부터 복구해 나가는 것이 바람직하다.

6. 데이터 모니터링 및 정확성

집계 결과는 RTB 및 청구서 발행 목적으로 사용될 수 있다.

 

지속적 모니터링

  • 지연 시간: 데이터를 처리하는 각 단계마다 지연시간이 추가될 수 있으므로, 시스템의 중요 부분마다 시각 추적이 가능하도록 해야 한다.
  • 메세지 큐 크기: 카프카를 사용하는 경우에는 레코드 처리 지연 지표를 대신 추적하면 된다.
  • 집계 노드의 시스템 자원: CPU, 디스크, JVM 같은 것에 관계된 지표

조정

  • 조정은 다양한 데이터를 비교하여 데이터 무결성을 보증하는 기법을 일컫는다.
  • 광고 클릭 집계 결과는 비교할 제 3자가 없다.
  • 한 가지 방법은 매일 각 파티션에 기록된 클릭 이벤트를 이벤트 발생 시각에 따라 정렬한 결과를 일괄 처리하여 만들어 낸 다음, 실시간 집계 결과와 비교해 보는 것이다.

7. 대안적 설계안

  • 다른 설계안은 광고 클릭 데이터를 하이브에 저장한 다음 빠른 질의는 엘라스틱서치 계층을 얹어서 처리하는 것이다.
  • 집계는 클릭하우스나 드루이드 같은 OLAP 데이터베이스를 통해 처리할 수 있다.